diff options
Diffstat (limited to 'xbmc/addons/interfaces')
68 files changed, 13370 insertions, 0 deletions
diff --git a/xbmc/addons/interfaces/AddonBase.cpp b/xbmc/addons/interfaces/AddonBase.cpp new file mode 100644 index 0000000..496ca92 --- /dev/null +++ b/xbmc/addons/interfaces/AddonBase.cpp @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "AddonBase.h" + +#include "GUIUserMessages.h" +#include "addons/AddonManager.h" +#include "addons/addoninfo/AddonInfo.h" +#include "addons/addoninfo/AddonType.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/gui/GUIDialogAddonSettings.h" +#include "addons/settings/AddonSettings.h" +#include "application/Application.h" +#include "filesystem/Directory.h" +#include "filesystem/SpecialProtocol.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "settings/lib/Setting.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +// "C" interface addon callback handle classes +#include "AudioEngine.h" +#include "Filesystem.h" +#include "General.h" +#include "Network.h" +#include "gui/General.h" + +namespace ADDON +{ + +std::vector<ADDON_GET_INTERFACE_FN> Interface_Base::s_registeredInterfaces; + +bool Interface_Base::InitInterface(CAddonDll* addon, + AddonGlobalInterface& addonInterface, + KODI_ADDON_INSTANCE_STRUCT* firstKodiInstance) +{ + addonInterface = {}; + + addonInterface.addonBase = nullptr; + addonInterface.globalSingleInstance = nullptr; + addonInterface.firstKodiInstance = firstKodiInstance; + + // Create function list from kodi to addon, generated with malloc to have + // compatible with other versions + addonInterface.toKodi = new AddonToKodiFuncTable_Addon(); + addonInterface.toKodi->kodiBase = addon; + addonInterface.toKodi->addon_log_msg = addon_log_msg; + addonInterface.toKodi->free_string = free_string; + addonInterface.toKodi->free_string_array = free_string_array; + + addonInterface.toKodi->kodi_addon = new AddonToKodiFuncTable_kodi_addon(); + addonInterface.toKodi->kodi_addon->get_addon_path = get_addon_path; + addonInterface.toKodi->kodi_addon->get_lib_path = get_lib_path; + addonInterface.toKodi->kodi_addon->get_user_path = get_user_path; + addonInterface.toKodi->kodi_addon->get_temp_path = get_temp_path; + addonInterface.toKodi->kodi_addon->get_localized_string = get_localized_string; + addonInterface.toKodi->kodi_addon->open_settings_dialog = open_settings_dialog; + addonInterface.toKodi->kodi_addon->is_setting_using_default = is_setting_using_default; + addonInterface.toKodi->kodi_addon->get_setting_bool = get_setting_bool; + addonInterface.toKodi->kodi_addon->get_setting_int = get_setting_int; + addonInterface.toKodi->kodi_addon->get_setting_float = get_setting_float; + addonInterface.toKodi->kodi_addon->get_setting_string = get_setting_string; + addonInterface.toKodi->kodi_addon->set_setting_bool = set_setting_bool; + addonInterface.toKodi->kodi_addon->set_setting_int = set_setting_int; + addonInterface.toKodi->kodi_addon->set_setting_float = set_setting_float; + addonInterface.toKodi->kodi_addon->set_setting_string = set_setting_string; + addonInterface.toKodi->kodi_addon->get_addon_info = get_addon_info; + addonInterface.toKodi->kodi_addon->get_type_version = get_type_version; + addonInterface.toKodi->kodi_addon->get_interface = get_interface; + + // Related parts becomes set from addon headers, make here to nullptr to allow + // checks for right set of them + addonInterface.toAddon = new KodiToAddonFuncTable_Addon(); + + // Init the other interfaces + Interface_General::Init(&addonInterface); + Interface_AudioEngine::Init(&addonInterface); + Interface_Filesystem::Init(&addonInterface); + Interface_Network::Init(&addonInterface); + Interface_GUIGeneral::Init(&addonInterface); + + return true; +} + +void Interface_Base::DeInitInterface(AddonGlobalInterface& addonInterface) +{ + Interface_GUIGeneral::DeInit(&addonInterface); + Interface_Network::DeInit(&addonInterface); + Interface_Filesystem::DeInit(&addonInterface); + Interface_AudioEngine::DeInit(&addonInterface); + Interface_General::DeInit(&addonInterface); + + if (addonInterface.toKodi) + delete addonInterface.toKodi->kodi_addon; + delete addonInterface.toKodi; + delete addonInterface.toAddon; + addonInterface = {}; +} + +void Interface_Base::RegisterInterface(ADDON_GET_INTERFACE_FN fn) +{ + s_registeredInterfaces.push_back(fn); +} + +bool Interface_Base::UpdateSettingInActiveDialog(CAddonDll* addon, + AddonInstanceId instanceId, + const char* id, + const std::string& value) +{ + if (!CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_DIALOG_ADDON_SETTINGS)) + return false; + + CGUIDialogAddonSettings* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogAddonSettings>( + WINDOW_DIALOG_ADDON_SETTINGS); + if (dialog->GetCurrentAddonID() != addon->ID()) + return false; + + CGUIMessage message(GUI_MSG_SETTING_UPDATED, 0, 0); + std::vector<std::string> params; + params.emplace_back(id); + params.push_back(value); + message.SetStringParams(params); + message.SetParam1(instanceId); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message, + WINDOW_DIALOG_ADDON_SETTINGS); + + return true; +} + +/*! + * @brief Addon to Kodi basic callbacks below + * + * The amount of functions here are hold so minimal as possible. Only parts + * where needed on nearly every add-on (e.g. addon_log_msg) are to add there. + * + * More specific parts like e.g. to open files should be added to a separate + * part. + */ +//@{ + +void Interface_Base::addon_log_msg(const KODI_ADDON_BACKEND_HDL hdl, + const int addonLogLevel, + const char* strMessage) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "addon_log_msg(...) called with empty kodi instance pointer"); + return; + } + + int logLevel = LOGNONE; + switch (addonLogLevel) + { + case ADDON_LOG_DEBUG: + logLevel = LOGDEBUG; + break; + case ADDON_LOG_INFO: + logLevel = LOGINFO; + break; + case ADDON_LOG_WARNING: + logLevel = LOGWARNING; + break; + case ADDON_LOG_ERROR: + logLevel = LOGERROR; + break; + case ADDON_LOG_FATAL: + logLevel = LOGFATAL; + break; + default: + logLevel = LOGDEBUG; + break; + } + + CLog::Log(logLevel, "AddOnLog: {}: {}", addon->ID(), strMessage); +} + +char* Interface_Base::get_type_version(const KODI_ADDON_BACKEND_HDL hdl, int type) +{ + return strdup(kodi::addon::GetTypeVersion(type)); +} + +char* Interface_Base::get_addon_path(const KODI_ADDON_BACKEND_HDL hdl) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "get_addon_path(...) called with empty kodi instance pointer"); + return nullptr; + } + + return strdup(CSpecialProtocol::TranslatePath(addon->Path()).c_str()); +} + +char* Interface_Base::get_lib_path(const KODI_ADDON_BACKEND_HDL hdl) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "get_lib_path(...) called with empty kodi instance pointer"); + return nullptr; + } + + return strdup(CSpecialProtocol::TranslatePath("special://xbmcbinaddons/" + addon->ID()).c_str()); +} + +char* Interface_Base::get_user_path(const KODI_ADDON_BACKEND_HDL hdl) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "get_user_path(...) called with empty kodi instance pointer"); + return nullptr; + } + + return strdup(CSpecialProtocol::TranslatePath(addon->Profile()).c_str()); +} + +char* Interface_Base::get_temp_path(const KODI_ADDON_BACKEND_HDL hdl) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "get_temp_path(...) called with empty kodi instance pointer"); + return nullptr; + } + + std::string tempPath = + URIUtils::AddFileToFolder(CServiceBroker::GetAddonMgr().GetTempAddonBasePath(), addon->ID()); + tempPath += "-temp"; + XFILE::CDirectory::Create(tempPath); + + return strdup(CSpecialProtocol::TranslatePath(tempPath).c_str()); +} + +char* Interface_Base::get_localized_string(const KODI_ADDON_BACKEND_HDL hdl, long label_id) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (!addon) + { + CLog::Log(LOGERROR, "get_localized_string(...) called with empty kodi instance pointer"); + return nullptr; + } + + if (g_application.m_bStop) + return nullptr; + + std::string label = g_localizeStrings.GetAddonString(addon->ID(), label_id); + if (label.empty()) + label = g_localizeStrings.Get(label_id); + char* buffer = strdup(label.c_str()); + return buffer; +} + +char* Interface_Base::get_addon_info(const KODI_ADDON_BACKEND_HDL hdl, const char* id) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr) + { + CLog::Log(LOGERROR, "get_addon_info(...) called with empty pointer"); + return nullptr; + } + + std::string str; + if (StringUtils::CompareNoCase(id, "author") == 0) + str = addon->Author(); + else if (StringUtils::CompareNoCase(id, "changelog") == 0) + str = addon->ChangeLog(); + else if (StringUtils::CompareNoCase(id, "description") == 0) + str = addon->Description(); + else if (StringUtils::CompareNoCase(id, "disclaimer") == 0) + str = addon->Disclaimer(); + else if (StringUtils::CompareNoCase(id, "fanart") == 0) + str = addon->FanArt(); + else if (StringUtils::CompareNoCase(id, "icon") == 0) + str = addon->Icon(); + else if (StringUtils::CompareNoCase(id, "id") == 0) + str = addon->ID(); + else if (StringUtils::CompareNoCase(id, "name") == 0) + str = addon->Name(); + else if (StringUtils::CompareNoCase(id, "path") == 0) + str = addon->Path(); + else if (StringUtils::CompareNoCase(id, "profile") == 0) + str = addon->Profile(); + else if (StringUtils::CompareNoCase(id, "summary") == 0) + str = addon->Summary(); + else if (StringUtils::CompareNoCase(id, "type") == 0) + str = ADDON::CAddonInfo::TranslateType(addon->Type()); + else if (StringUtils::CompareNoCase(id, "version") == 0) + str = addon->Version().asString(); + else + { + CLog::Log(LOGERROR, "Interface_Base::{} - add-on '{}' requests invalid id '{}'", __func__, + addon->Name(), id); + return nullptr; + } + + char* buffer = strdup(str.c_str()); + return buffer; +} + +bool Interface_Base::open_settings_dialog(const KODI_ADDON_BACKEND_HDL hdl) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "open_settings_dialog(...) called with empty kodi instance pointer"); + return false; + } + + // show settings dialog + AddonPtr addonInfo; + if (!CServiceBroker::GetAddonMgr().GetAddon(addon->ID(), addonInfo, OnlyEnabled::CHOICE_YES)) + { + CLog::Log(LOGERROR, "Interface_Base::{} - Could not get addon information for '{}'", __func__, + addon->ID()); + return false; + } + + return CGUIDialogAddonSettings::ShowForAddon(addonInfo); +} + +bool Interface_Base::is_setting_using_default(const KODI_ADDON_BACKEND_HDL hdl, const char* id) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__, hdl, + static_cast<const void*>(id)); + + return false; + } + + if (!addon->HasSettings()) + { + CLog::Log(LOGERROR, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__, + addon->Name()); + return false; + } + + auto setting = addon->GetSettings()->GetSetting(id); + if (setting == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__, id, + addon->Name()); + return false; + } + + return setting->IsDefault(); +} + +bool Interface_Base::get_setting_bool(const KODI_ADDON_BACKEND_HDL hdl, const char* id, bool* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr || value == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')", + __func__, hdl, static_cast<const void*>(id), static_cast<void*>(value)); + + return false; + } + + if (!addon->HasSettings()) + { + CLog::Log(LOGERROR, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__, + addon->Name()); + return false; + } + + auto setting = addon->GetSettings()->GetSetting(id); + if (setting == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__, id, + addon->Name()); + return false; + } + + if (setting->GetType() != SettingType::Boolean) + { + CLog::Log(LOGERROR, "Interface_Base::{} - setting '{}' is not a boolean in '{}'", __func__, id, + addon->Name()); + return false; + } + + *value = std::static_pointer_cast<CSettingBool>(setting)->GetValue(); + return true; +} + +bool Interface_Base::get_setting_int(const KODI_ADDON_BACKEND_HDL hdl, const char* id, int* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr || value == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')", + __func__, hdl, static_cast<const void*>(id), static_cast<void*>(value)); + + return false; + } + + if (!addon->HasSettings()) + { + CLog::Log(LOGERROR, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__, + addon->Name()); + return false; + } + + auto setting = addon->GetSettings()->GetSetting(id); + if (setting == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__, id, + addon->Name()); + return false; + } + + if (setting->GetType() != SettingType::Integer && setting->GetType() != SettingType::Number) + { + CLog::Log(LOGERROR, "Interface_Base::{} - setting '{}' is not a integer in '{}'", __func__, id, + addon->Name()); + return false; + } + + if (setting->GetType() == SettingType::Integer) + *value = std::static_pointer_cast<CSettingInt>(setting)->GetValue(); + else + *value = static_cast<int>(std::static_pointer_cast<CSettingNumber>(setting)->GetValue()); + return true; +} + +bool Interface_Base::get_setting_float(const KODI_ADDON_BACKEND_HDL hdl, + const char* id, + float* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr || value == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')", + __func__, hdl, static_cast<const void*>(id), static_cast<void*>(value)); + + return false; + } + + if (!addon->HasSettings()) + { + CLog::Log(LOGERROR, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__, + addon->Name()); + return false; + } + + auto setting = addon->GetSettings()->GetSetting(id); + if (setting == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__, id, + addon->Name()); + return false; + } + + if (setting->GetType() != SettingType::Number) + { + CLog::Log(LOGERROR, "Interface_Base::{} - setting '{}' is not a number in '{}'", __func__, id, + addon->Name()); + return false; + } + + *value = static_cast<float>(std::static_pointer_cast<CSettingNumber>(setting)->GetValue()); + return true; +} + +bool Interface_Base::get_setting_string(const KODI_ADDON_BACKEND_HDL hdl, + const char* id, + char** value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr || value == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')", + __func__, hdl, static_cast<const void*>(id), static_cast<void*>(value)); + + return false; + } + + if (!addon->HasSettings()) + { + CLog::Log(LOGERROR, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__, + addon->Name()); + return false; + } + + auto setting = addon->GetSettings()->GetSetting(id); + if (setting == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__, id, + addon->Name()); + return false; + } + + if (setting->GetType() != SettingType::String) + { + CLog::Log(LOGERROR, "Interface_Base::{} - setting '{}' is not a string in '{}'", __func__, id, + addon->Name()); + return false; + } + + *value = strdup(std::static_pointer_cast<CSettingString>(setting)->GetValue().c_str()); + return true; +} + +bool Interface_Base::set_setting_bool(const KODI_ADDON_BACKEND_HDL hdl, const char* id, bool value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__, hdl, + static_cast<const void*>(id)); + + return false; + } + + if (Interface_Base::UpdateSettingInActiveDialog(addon, ADDON_SETTINGS_ID, id, + value ? "true" : "false")) + return true; + + if (!addon->UpdateSettingBool(id, value)) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid setting type", __func__); + return false; + } + + addon->SaveSettings(); + + return true; +} + +bool Interface_Base::set_setting_int(const KODI_ADDON_BACKEND_HDL hdl, const char* id, int value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__, hdl, + static_cast<const void*>(id)); + + return false; + } + + if (Interface_Base::UpdateSettingInActiveDialog(addon, ADDON_SETTINGS_ID, id, + std::to_string(value))) + return true; + + if (!addon->UpdateSettingInt(id, value)) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid setting type", __func__); + return false; + } + + addon->SaveSettings(); + + return true; +} + +bool Interface_Base::set_setting_float(const KODI_ADDON_BACKEND_HDL hdl, + const char* id, + float value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__, hdl, + static_cast<const void*>(id)); + + return false; + } + + if (Interface_Base::UpdateSettingInActiveDialog(addon, ADDON_SETTINGS_ID, id, + StringUtils::Format("{:f}", value))) + return true; + + if (!addon->UpdateSettingNumber(id, static_cast<double>(value))) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid setting type", __func__); + return false; + } + + addon->SaveSettings(); + + return true; +} + +bool Interface_Base::set_setting_string(const KODI_ADDON_BACKEND_HDL hdl, + const char* id, + const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(hdl); + if (addon == nullptr || id == nullptr || value == nullptr) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')", + __func__, hdl, static_cast<const void*>(id), static_cast<const void*>(value)); + + return false; + } + + if (Interface_Base::UpdateSettingInActiveDialog(addon, ADDON_SETTINGS_ID, id, value)) + return true; + + if (!addon->UpdateSettingString(id, value)) + { + CLog::Log(LOGERROR, "Interface_Base::{} - invalid setting type", __func__); + return false; + } + + addon->SaveSettings(); + + return true; +} + +void Interface_Base::free_string(const KODI_ADDON_BACKEND_HDL hdl, char* str) +{ + if (str) + free(str); +} + +void Interface_Base::free_string_array(const KODI_ADDON_BACKEND_HDL hdl, + char** arr, + int numElements) +{ + if (arr) + { + for (int i = 0; i < numElements; ++i) + { + free(arr[i]); + } + free(arr); + } +} + +void* Interface_Base::get_interface(const KODI_ADDON_BACKEND_HDL hdl, + const char* name, + const char* version) +{ + if (!name || !version) + return nullptr; + + void* retval(nullptr); + + for (auto fn : s_registeredInterfaces) + if ((retval = fn(name, version))) + break; + + return retval; +} + +//@} + +} // namespace ADDON diff --git a/xbmc/addons/interfaces/AddonBase.h b/xbmc/addons/interfaces/AddonBase.h new file mode 100644 index 0000000..6dcc53c --- /dev/null +++ b/xbmc/addons/interfaces/AddonBase.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/IAddon.h" +#include "addons/kodi-dev-kit/include/kodi/c-api/addon_base.h" + +extern "C" +{ +namespace ADDON +{ + +typedef void* (*ADDON_GET_INTERFACE_FN)(const std::string& name, const std::string& version); + +class CAddonDll; + +/*! + * @brief Global general Add-on to Kodi callback functions + * + * To hold general functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/General.h" + */ +struct Interface_Base +{ + static bool InitInterface(CAddonDll* addon, + AddonGlobalInterface& addonInterface, + KODI_ADDON_INSTANCE_STRUCT* firstKodiInstance); + static void DeInitInterface(AddonGlobalInterface& addonInterface); + static void RegisterInterface(ADDON_GET_INTERFACE_FN fn); + static bool UpdateSettingInActiveDialog(CAddonDll* addon, + AddonInstanceId instanceId, + const char* id, + const std::string& value); + + static std::vector<ADDON_GET_INTERFACE_FN> s_registeredInterfaces; + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void addon_log_msg(const KODI_ADDON_BACKEND_HDL hdl, + const int addonLogLevel, + const char* strMessage); + static char* get_type_version(const KODI_ADDON_BACKEND_HDL hdl, int type); + static char* get_addon_path(const KODI_ADDON_BACKEND_HDL hdl); + static char* get_lib_path(const KODI_ADDON_BACKEND_HDL hdl); + static char* get_user_path(const KODI_ADDON_BACKEND_HDL hdl); + static char* get_temp_path(const KODI_ADDON_BACKEND_HDL hdl); + static char* get_localized_string(const KODI_ADDON_BACKEND_HDL hdl, long label_id); + static char* get_addon_info(const KODI_ADDON_BACKEND_HDL hdl, const char* id); + static bool open_settings_dialog(const KODI_ADDON_BACKEND_HDL hdl); + static bool is_setting_using_default(const KODI_ADDON_BACKEND_HDL hdl, const char* id); + static bool get_setting_bool(const KODI_ADDON_BACKEND_HDL hdl, const char* id, bool* value); + static bool get_setting_int(const KODI_ADDON_BACKEND_HDL hdl, const char* id, int* value); + static bool get_setting_float(const KODI_ADDON_BACKEND_HDL hdl, const char* id, float* value); + static bool get_setting_string(const KODI_ADDON_BACKEND_HDL hdl, const char* id, char** value); + static bool set_setting_bool(const KODI_ADDON_BACKEND_HDL hdl, const char* id, bool value); + static bool set_setting_int(const KODI_ADDON_BACKEND_HDL hdl, const char* id, int value); + static bool set_setting_float(const KODI_ADDON_BACKEND_HDL hdl, const char* id, float value); + static bool set_setting_string(const KODI_ADDON_BACKEND_HDL hdl, + const char* id, + const char* value); + static void free_string(const KODI_ADDON_BACKEND_HDL hdl, char* str); + static void free_string_array(const KODI_ADDON_BACKEND_HDL hdl, char** arr, int numElements); + static void* get_interface(const KODI_ADDON_BACKEND_HDL hdl, + const char* name, + const char* version); + //@} +}; + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/AudioEngine.cpp b/xbmc/addons/interfaces/AudioEngine.cpp new file mode 100644 index 0000000..0efcc07 --- /dev/null +++ b/xbmc/addons/interfaces/AudioEngine.cpp @@ -0,0 +1,761 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "AudioEngine.h" + +#include "ServiceBroker.h" +#include "addons/kodi-dev-kit/include/kodi/AddonBase.h" +#include "cores/AudioEngine/Interfaces/AE.h" +#include "cores/AudioEngine/Interfaces/AEStream.h" +#include "cores/AudioEngine/Utils/AEStreamData.h" +#include "utils/log.h" + +using namespace kodi; // addon-dev-kit namespace +using namespace kodi::audioengine; // addon-dev-kit namespace + +namespace ADDON +{ + +void Interface_AudioEngine::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_audioengine = new AddonToKodiFuncTable_kodi_audioengine(); + + // write KODI audio DSP specific add-on function addresses to callback table + addonInterface->toKodi->kodi_audioengine->make_stream = audioengine_make_stream; + addonInterface->toKodi->kodi_audioengine->free_stream = audioengine_free_stream; + addonInterface->toKodi->kodi_audioengine->get_current_sink_format = get_current_sink_format; + + // AEStream add-on function callback table + addonInterface->toKodi->kodi_audioengine->aestream_get_space = aestream_get_space; + addonInterface->toKodi->kodi_audioengine->aestream_add_data = aestream_add_data; + addonInterface->toKodi->kodi_audioengine->aestream_get_delay = aestream_get_delay; + addonInterface->toKodi->kodi_audioengine->aestream_is_buffering = aestream_is_buffering; + addonInterface->toKodi->kodi_audioengine->aestream_get_cache_time = aestream_get_cache_time; + addonInterface->toKodi->kodi_audioengine->aestream_get_cache_total = aestream_get_cache_total; + addonInterface->toKodi->kodi_audioengine->aestream_pause = aestream_pause; + addonInterface->toKodi->kodi_audioengine->aestream_resume = aestream_resume; + addonInterface->toKodi->kodi_audioengine->aestream_drain = aestream_drain; + addonInterface->toKodi->kodi_audioengine->aestream_is_draining = aestream_is_draining; + addonInterface->toKodi->kodi_audioengine->aestream_is_drained = aestream_is_drained; + addonInterface->toKodi->kodi_audioengine->aestream_flush = aestream_flush; + addonInterface->toKodi->kodi_audioengine->aestream_get_volume = aestream_get_volume; + addonInterface->toKodi->kodi_audioengine->aestream_set_volume = aestream_set_volume; + addonInterface->toKodi->kodi_audioengine->aestream_get_amplification = aestream_get_amplification; + addonInterface->toKodi->kodi_audioengine->aestream_set_amplification = aestream_set_amplification; + addonInterface->toKodi->kodi_audioengine->aestream_get_frame_size = aestream_get_frame_size; + addonInterface->toKodi->kodi_audioengine->aestream_get_channel_count = aestream_get_channel_count; + addonInterface->toKodi->kodi_audioengine->aestream_get_sample_rate = aestream_get_sample_rate; + addonInterface->toKodi->kodi_audioengine->aestream_get_data_format = aestream_get_data_format; + addonInterface->toKodi->kodi_audioengine->aestream_get_resample_ratio = + aestream_get_resample_ratio; + addonInterface->toKodi->kodi_audioengine->aestream_set_resample_ratio = + aestream_set_resample_ratio; +} + +void Interface_AudioEngine::DeInit(AddonGlobalInterface* addonInterface) +{ + if (addonInterface->toKodi) /* <-- Safe check, needed so long old addon way is present */ + { + delete addonInterface->toKodi->kodi_audioengine; + addonInterface->toKodi->kodi_audioengine = nullptr; + } +} + +AEChannel Interface_AudioEngine::TranslateAEChannelToKodi(AudioEngineChannel channel) +{ + switch (channel) + { + case AUDIOENGINE_CH_RAW: + return AE_CH_RAW; + case AUDIOENGINE_CH_FL: + return AE_CH_FL; + case AUDIOENGINE_CH_FR: + return AE_CH_FR; + case AUDIOENGINE_CH_FC: + return AE_CH_FC; + case AUDIOENGINE_CH_LFE: + return AE_CH_LFE; + case AUDIOENGINE_CH_BL: + return AE_CH_BL; + case AUDIOENGINE_CH_BR: + return AE_CH_BR; + case AUDIOENGINE_CH_FLOC: + return AE_CH_FLOC; + case AUDIOENGINE_CH_FROC: + return AE_CH_FROC; + case AUDIOENGINE_CH_BC: + return AE_CH_BC; + case AUDIOENGINE_CH_SL: + return AE_CH_SL; + case AUDIOENGINE_CH_SR: + return AE_CH_SR; + case AUDIOENGINE_CH_TFL: + return AE_CH_TFL; + case AUDIOENGINE_CH_TFR: + return AE_CH_TFR; + case AUDIOENGINE_CH_TFC: + return AE_CH_TFC; + case AUDIOENGINE_CH_TC: + return AE_CH_TC; + case AUDIOENGINE_CH_TBL: + return AE_CH_TBL; + case AUDIOENGINE_CH_TBR: + return AE_CH_TBR; + case AUDIOENGINE_CH_TBC: + return AE_CH_TBC; + case AUDIOENGINE_CH_BLOC: + return AE_CH_BLOC; + case AUDIOENGINE_CH_BROC: + return AE_CH_BROC; + case AUDIOENGINE_CH_MAX: + return AE_CH_MAX; + case AUDIOENGINE_CH_NULL: + default: + return AE_CH_NULL; + } +} + +AudioEngineChannel Interface_AudioEngine::TranslateAEChannelToAddon(AEChannel channel) +{ + switch (channel) + { + case AE_CH_RAW: + return AUDIOENGINE_CH_RAW; + case AE_CH_FL: + return AUDIOENGINE_CH_FL; + case AE_CH_FR: + return AUDIOENGINE_CH_FR; + case AE_CH_FC: + return AUDIOENGINE_CH_FC; + case AE_CH_LFE: + return AUDIOENGINE_CH_LFE; + case AE_CH_BL: + return AUDIOENGINE_CH_BL; + case AE_CH_BR: + return AUDIOENGINE_CH_BR; + case AE_CH_FLOC: + return AUDIOENGINE_CH_FLOC; + case AE_CH_FROC: + return AUDIOENGINE_CH_FROC; + case AE_CH_BC: + return AUDIOENGINE_CH_BC; + case AE_CH_SL: + return AUDIOENGINE_CH_SL; + case AE_CH_SR: + return AUDIOENGINE_CH_SR; + case AE_CH_TFL: + return AUDIOENGINE_CH_TFL; + case AE_CH_TFR: + return AUDIOENGINE_CH_TFR; + case AE_CH_TFC: + return AUDIOENGINE_CH_TFC; + case AE_CH_TC: + return AUDIOENGINE_CH_TC; + case AE_CH_TBL: + return AUDIOENGINE_CH_TBL; + case AE_CH_TBR: + return AUDIOENGINE_CH_TBR; + case AE_CH_TBC: + return AUDIOENGINE_CH_TBC; + case AE_CH_BLOC: + return AUDIOENGINE_CH_BLOC; + case AE_CH_BROC: + return AUDIOENGINE_CH_BROC; + case AE_CH_MAX: + return AUDIOENGINE_CH_MAX; + case AE_CH_NULL: + default: + return AUDIOENGINE_CH_NULL; + } +} + +AEDataFormat Interface_AudioEngine::TranslateAEFormatToKodi(AudioEngineDataFormat format) +{ + switch (format) + { + case AUDIOENGINE_FMT_U8: + return AE_FMT_U8; + case AUDIOENGINE_FMT_S16BE: + return AE_FMT_S16BE; + case AUDIOENGINE_FMT_S16LE: + return AE_FMT_S16LE; + case AUDIOENGINE_FMT_S16NE: + return AE_FMT_S16NE; + case AUDIOENGINE_FMT_S32BE: + return AE_FMT_S32BE; + case AUDIOENGINE_FMT_S32LE: + return AE_FMT_S32LE; + case AUDIOENGINE_FMT_S32NE: + return AE_FMT_S32NE; + case AUDIOENGINE_FMT_S24BE4: + return AE_FMT_S24BE4; + case AUDIOENGINE_FMT_S24LE4: + return AE_FMT_S24LE4; + case AUDIOENGINE_FMT_S24NE4: + return AE_FMT_S24NE4; + case AUDIOENGINE_FMT_S24NE4MSB: + return AE_FMT_S24NE4MSB; + case AUDIOENGINE_FMT_S24BE3: + return AE_FMT_S24BE3; + case AUDIOENGINE_FMT_S24LE3: + return AE_FMT_S24LE3; + case AUDIOENGINE_FMT_S24NE3: + return AE_FMT_S24NE3; + case AUDIOENGINE_FMT_DOUBLE: + return AE_FMT_DOUBLE; + case AUDIOENGINE_FMT_FLOAT: + return AE_FMT_FLOAT; + case AUDIOENGINE_FMT_RAW: + return AE_FMT_RAW; + case AUDIOENGINE_FMT_U8P: + return AE_FMT_U8P; + case AUDIOENGINE_FMT_S16NEP: + return AE_FMT_S16NEP; + case AUDIOENGINE_FMT_S32NEP: + return AE_FMT_S32NEP; + case AUDIOENGINE_FMT_S24NE4P: + return AE_FMT_S24NE4P; + case AUDIOENGINE_FMT_S24NE4MSBP: + return AE_FMT_S24NE4MSBP; + case AUDIOENGINE_FMT_S24NE3P: + return AE_FMT_S24NE3P; + case AUDIOENGINE_FMT_DOUBLEP: + return AE_FMT_DOUBLEP; + case AUDIOENGINE_FMT_FLOATP: + return AE_FMT_FLOATP; + case AUDIOENGINE_FMT_MAX: + return AE_FMT_MAX; + case AUDIOENGINE_FMT_INVALID: + default: + return AE_FMT_INVALID; + } +} + +AudioEngineDataFormat Interface_AudioEngine::TranslateAEFormatToAddon(AEDataFormat format) +{ + switch (format) + { + case AE_FMT_U8: + return AUDIOENGINE_FMT_U8; + case AE_FMT_S16BE: + return AUDIOENGINE_FMT_S16BE; + case AE_FMT_S16LE: + return AUDIOENGINE_FMT_S16LE; + case AE_FMT_S16NE: + return AUDIOENGINE_FMT_S16NE; + case AE_FMT_S32BE: + return AUDIOENGINE_FMT_S32BE; + case AE_FMT_S32LE: + return AUDIOENGINE_FMT_S32LE; + case AE_FMT_S32NE: + return AUDIOENGINE_FMT_S32NE; + case AE_FMT_S24BE4: + return AUDIOENGINE_FMT_S24BE4; + case AE_FMT_S24LE4: + return AUDIOENGINE_FMT_S24LE4; + case AE_FMT_S24NE4: + return AUDIOENGINE_FMT_S24NE4; + case AE_FMT_S24NE4MSB: + return AUDIOENGINE_FMT_S24NE4MSB; + case AE_FMT_S24BE3: + return AUDIOENGINE_FMT_S24BE3; + case AE_FMT_S24LE3: + return AUDIOENGINE_FMT_S24LE3; + case AE_FMT_S24NE3: + return AUDIOENGINE_FMT_S24NE3; + case AE_FMT_DOUBLE: + return AUDIOENGINE_FMT_DOUBLE; + case AE_FMT_FLOAT: + return AUDIOENGINE_FMT_FLOAT; + case AE_FMT_RAW: + return AUDIOENGINE_FMT_RAW; + case AE_FMT_U8P: + return AUDIOENGINE_FMT_U8P; + case AE_FMT_S16NEP: + return AUDIOENGINE_FMT_S16NEP; + case AE_FMT_S32NEP: + return AUDIOENGINE_FMT_S32NEP; + case AE_FMT_S24NE4P: + return AUDIOENGINE_FMT_S24NE4P; + case AE_FMT_S24NE4MSBP: + return AUDIOENGINE_FMT_S24NE4MSBP; + case AE_FMT_S24NE3P: + return AUDIOENGINE_FMT_S24NE3P; + case AE_FMT_DOUBLEP: + return AUDIOENGINE_FMT_DOUBLEP; + case AE_FMT_FLOATP: + return AUDIOENGINE_FMT_FLOATP; + case AE_FMT_MAX: + return AUDIOENGINE_FMT_MAX; + case AE_FMT_INVALID: + default: + return AUDIOENGINE_FMT_INVALID; + } +} + +AEStreamHandle* Interface_AudioEngine::audioengine_make_stream(void* kodiBase, + AUDIO_ENGINE_FORMAT* streamFormat, + unsigned int options) +{ + if (!kodiBase || !streamFormat) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamFormat='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamFormat)); + return nullptr; + } + + IAE* engine = CServiceBroker::GetActiveAE(); + if (!engine) + return nullptr; + + CAEChannelInfo layout; + for (unsigned int ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) + { + if (streamFormat->m_channels[ch] == AUDIOENGINE_CH_NULL) + break; + layout += TranslateAEChannelToKodi(streamFormat->m_channels[ch]); + } + + AEAudioFormat format; + format.m_channelLayout = layout; + format.m_dataFormat = TranslateAEFormatToKodi(streamFormat->m_dataFormat); + format.m_sampleRate = streamFormat->m_sampleRate; + + /* Translate addon options to kodi's options */ + int kodiOption = 0; + if (options & AUDIO_STREAM_FORCE_RESAMPLE) + kodiOption |= AESTREAM_FORCE_RESAMPLE; + if (options & AUDIO_STREAM_PAUSED) + kodiOption |= AESTREAM_PAUSED; + if (options & AUDIO_STREAM_AUTOSTART) + kodiOption |= AESTREAM_AUTOSTART; + + return engine->MakeStream(format, kodiOption).release(); +} + +void Interface_AudioEngine::audioengine_free_stream(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + IAE* engine = CServiceBroker::GetActiveAE(); + if (engine) + engine->FreeStream(static_cast<IAEStream*>(streamHandle), true); +} + +bool Interface_AudioEngine::get_current_sink_format(void* kodiBase, AUDIO_ENGINE_FORMAT* format) +{ + if (!kodiBase || !format) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', format='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(format)); + return false; + } + + IAE* engine = CServiceBroker::GetActiveAE(); + if (!engine) + return false; + + AEAudioFormat sinkFormat; + if (!engine->GetCurrentSinkFormat(sinkFormat)) + { + CLog::Log(LOGERROR, "Interface_AudioEngine::{} - failed to get current sink format from AE!", + __FUNCTION__); + return false; + } + + format->m_dataFormat = TranslateAEFormatToAddon(sinkFormat.m_dataFormat); + format->m_sampleRate = sinkFormat.m_sampleRate; + format->m_frames = sinkFormat.m_frames; + format->m_frameSize = sinkFormat.m_frameSize; + format->m_channelCount = sinkFormat.m_channelLayout.Count(); + for (unsigned int ch = 0; ch < format->m_channelCount && ch < AUDIOENGINE_CH_MAX; ++ch) + { + format->m_channels[ch] = TranslateAEChannelToAddon(sinkFormat.m_channelLayout[ch]); + } + + return true; +} + +unsigned int Interface_AudioEngine::aestream_get_space(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return 0; + } + + return static_cast<IAEStream*>(streamHandle)->GetSpace(); +} + +unsigned int Interface_AudioEngine::aestream_add_data(void* kodiBase, + AEStreamHandle* streamHandle, + uint8_t* const* data, + unsigned int offset, + unsigned int frames, + double pts, + bool hasDownmix, + double centerMixLevel) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return 0; + } + + if (!CServiceBroker::GetActiveAE()) + return 0; + + IAEStream::ExtData extData; + extData.pts = pts; + extData.hasDownmix = hasDownmix; + extData.centerMixLevel = centerMixLevel; + return static_cast<IAEStream*>(streamHandle)->AddData(data, offset, frames, &extData); +} + +double Interface_AudioEngine::aestream_get_delay(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return -1.0; + } + + if (!CServiceBroker::GetActiveAE()) + return -1.0; + + return static_cast<IAEStream*>(streamHandle)->GetDelay(); +} + +bool Interface_AudioEngine::aestream_is_buffering(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return false; + } + + if (!CServiceBroker::GetActiveAE()) + return false; + + return static_cast<IAEStream*>(streamHandle)->IsBuffering(); +} + +double Interface_AudioEngine::aestream_get_cache_time(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return -1.0; + } + + if (!CServiceBroker::GetActiveAE()) + return -1.0; + + return static_cast<IAEStream*>(streamHandle)->GetCacheTime(); +} + +double Interface_AudioEngine::aestream_get_cache_total(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return -1.0; + } + + if (!CServiceBroker::GetActiveAE()) + return -1.0; + + return static_cast<IAEStream*>(streamHandle)->GetCacheTotal(); +} + +void Interface_AudioEngine::aestream_pause(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + if (!CServiceBroker::GetActiveAE()) + return; + + static_cast<IAEStream*>(streamHandle)->Pause(); +} + +void Interface_AudioEngine::aestream_resume(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + static_cast<IAEStream*>(streamHandle)->Resume(); +} + +void Interface_AudioEngine::aestream_drain(void* kodiBase, AEStreamHandle* streamHandle, bool wait) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + if (!CServiceBroker::GetActiveAE()) + return; + + static_cast<IAEStream*>(streamHandle)->Drain(wait); +} + +bool Interface_AudioEngine::aestream_is_draining(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return false; + } + + if (!CServiceBroker::GetActiveAE()) + return false; + + return static_cast<IAEStream*>(streamHandle)->IsDraining(); +} + +bool Interface_AudioEngine::aestream_is_drained(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return false; + } + + if (!CServiceBroker::GetActiveAE()) + return false; + + return static_cast<IAEStream*>(streamHandle)->IsDrained(); +} + +void Interface_AudioEngine::aestream_flush(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + if (!CServiceBroker::GetActiveAE()) + return; + + static_cast<IAEStream*>(streamHandle)->Flush(); +} + +float Interface_AudioEngine::aestream_get_volume(void* kodiBase, AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return -1.0f; + } + + if (!CServiceBroker::GetActiveAE()) + return -1.0f; + + return static_cast<IAEStream*>(streamHandle)->GetVolume(); +} + +void Interface_AudioEngine::aestream_set_volume(void* kodiBase, + AEStreamHandle* streamHandle, + float volume) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + if (!CServiceBroker::GetActiveAE()) + return; + + static_cast<IAEStream*>(streamHandle)->SetVolume(volume); +} + +float Interface_AudioEngine::aestream_get_amplification(void* kodiBase, + AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return -1.0f; + } + + if (!CServiceBroker::GetActiveAE()) + return -1.0f; + + return static_cast<IAEStream*>(streamHandle)->GetAmplification(); +} + +void Interface_AudioEngine::aestream_set_amplification(void* kodiBase, + AEStreamHandle* streamHandle, + float amplify) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + if (!CServiceBroker::GetActiveAE()) + return; + + static_cast<IAEStream*>(streamHandle)->SetAmplification(amplify); +} + +unsigned int Interface_AudioEngine::aestream_get_frame_size(void* kodiBase, + AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return 0; + } + + if (!CServiceBroker::GetActiveAE()) + return 0; + + return static_cast<IAEStream*>(streamHandle)->GetFrameSize(); +} + +unsigned int Interface_AudioEngine::aestream_get_channel_count(void* kodiBase, + AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return 0; + } + + if (!CServiceBroker::GetActiveAE()) + return 0; + + return static_cast<IAEStream*>(streamHandle)->GetChannelCount(); +} + +unsigned int Interface_AudioEngine::aestream_get_sample_rate(void* kodiBase, + AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return 0; + } + + if (!CServiceBroker::GetActiveAE()) + return 0; + + return static_cast<IAEStream*>(streamHandle)->GetSampleRate(); +} + +AudioEngineDataFormat Interface_AudioEngine::aestream_get_data_format(void* kodiBase, + AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return AUDIOENGINE_FMT_INVALID; + } + + if (!CServiceBroker::GetActiveAE()) + return AUDIOENGINE_FMT_INVALID; + + return TranslateAEFormatToAddon(static_cast<IAEStream*>(streamHandle)->GetDataFormat()); +} + +double Interface_AudioEngine::aestream_get_resample_ratio(void* kodiBase, + AEStreamHandle* streamHandle) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return -1.0; + } + + if (!CServiceBroker::GetActiveAE()) + return -1.0; + + return static_cast<IAEStream*>(streamHandle)->GetResampleRatio(); +} + +void Interface_AudioEngine::aestream_set_resample_ratio(void* kodiBase, + AEStreamHandle* streamHandle, + double ratio) +{ + if (!kodiBase || !streamHandle) + { + CLog::Log(LOGERROR, + "Interface_AudioEngine::{} - invalid stream data (kodiBase='{}', streamHandle='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(streamHandle)); + return; + } + + if (!CServiceBroker::GetActiveAE()) + return; + + static_cast<IAEStream*>(streamHandle)->SetResampleRatio(ratio); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/AudioEngine.h b/xbmc/addons/interfaces/AudioEngine.h new file mode 100644 index 0000000..3700931 --- /dev/null +++ b/xbmc/addons/interfaces/AudioEngine.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/AudioEngine.h" +#include "cores/AudioEngine/Utils/AEChannelData.h" + +extern "C" +{ +namespace ADDON +{ + +struct Interface_AudioEngine +{ + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /** + * @brief Translation functions to separate Kodi and addons + * + * This thought to make it more safe for cases as something changed inside + * Kodi, addons overseen and breaks API, further to have on addons a better + * documentation about this parts. + */ + //@{ + static AEChannel TranslateAEChannelToKodi(AudioEngineChannel channel); + static AudioEngineChannel TranslateAEChannelToAddon(AEChannel channel); + static AEDataFormat TranslateAEFormatToKodi(AudioEngineDataFormat format); + static AudioEngineDataFormat TranslateAEFormatToAddon(AEDataFormat format); + //@} + + /** + * Creates and returns a new handle to an IAEStream in the format specified, this function should never fail + * @param[in] streamFormat Format to use for stream + * @param[in] options A bit field of stream options (see: enum AEStreamOptions) + * @return a new Handle to an IAEStream that will accept data in the requested format + */ + static AEStreamHandle* audioengine_make_stream(void* kodiBase, + AUDIO_ENGINE_FORMAT* streamFormat, + unsigned int options); + + /** + * This method will remove the specified stream from the engine. + * For OSX/IOS this is essential to reconfigure the audio output. + * @param[in] streamHandle The stream to be altered + */ + static void audioengine_free_stream(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Get the current sink data format + * + * @param[in] sinkFormat sink data format. For more details see AUDIO_ENGINE_FORMAT. + * @return Returns true on success, else false. + */ + static bool get_current_sink_format(void* kodiBase, AUDIO_ENGINE_FORMAT* sinkFormat); + + /** + * Returns the amount of space available in the stream + * @return The number of bytes AddData will consume + */ + static unsigned int aestream_get_space(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Add planar or interleaved PCM data to the stream + * @param[in] data array of pointers to the planes + * @param[in] offset to frame in frames + * @param[in] frames number of frames + * @return The number of frames consumed + */ + static unsigned int aestream_add_data(void* kodiBase, + AEStreamHandle* streamHandle, + uint8_t* const* data, + unsigned int offset, + unsigned int frames, + double pts, + bool hasDownmix, + double centerMixLevel); + + /** + * Returns the time in seconds that it will take + * for the next added packet to be heard from the speakers. + * @return seconds + */ + static double aestream_get_delay(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Returns if the stream is buffering + * @return True if the stream is buffering + */ + static bool aestream_is_buffering(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Returns the time in seconds that it will take + * to underrun the cache if no sample is added. + * @return seconds + */ + static double aestream_get_cache_time(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Returns the total time in seconds of the cache + * @return seconds + */ + static double aestream_get_cache_total(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Pauses the stream playback + */ + static void aestream_pause(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Resumes the stream after pausing + */ + static void aestream_resume(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Start draining the stream + * @note Once called AddData will not consume more data. + */ + static void aestream_drain(void* kodiBase, AEStreamHandle* streamHandle, bool wait); + + /** + * Returns true if the is stream draining + */ + static bool aestream_is_draining(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Returns true if the is stream has finished draining + */ + static bool aestream_is_drained(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Flush all buffers dropping the audio data + */ + static void aestream_flush(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Return the stream's current volume level + * @return The volume level between 0.0 and 1.0 + */ + static float aestream_get_volume(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Set the stream's volume level + * @param volume The new volume level between 0.0 and 1.0 + */ + static void aestream_set_volume(void* kodiBase, AEStreamHandle* streamHandle, float volume); + + /** + * Gets the stream's volume amplification in linear units. + * @return The volume amplification factor between 1.0 and 1000.0 + */ + static float aestream_get_amplification(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Sets the stream's volume amplification in linear units. + * @param amplify The volume amplification factor between 1.0 and 1000.0 + */ + static void aestream_set_amplification(void* kodiBase, + AEStreamHandle* streamHandle, + float amplify); + + /** + * Returns the size of one audio frame in bytes (channelCount * resolution) + * @return The size in bytes of one frame + */ + static unsigned int aestream_get_frame_size(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Returns the number of channels the stream is configured to accept + * @return The channel count + */ + static unsigned int aestream_get_channel_count(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Returns the stream's sample rate, if the stream is using a dynamic sample + * rate, this value will NOT reflect any changes made by calls to SetResampleRatio() + * @return The stream's sample rate (eg, 48000) + */ + static unsigned int aestream_get_sample_rate(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Return the data format the stream has been configured with + * @return The stream's data format (eg, AE_FMT_S16LE) + */ + static AudioEngineDataFormat aestream_get_data_format(void* kodiBase, + AEStreamHandle* streamHandle); + + /** + * Return the resample ratio + * @note This will return an undefined value if the stream is not resampling + * @return the current resample ratio or undefined if the stream is not resampling + */ + static double aestream_get_resample_ratio(void* kodiBase, AEStreamHandle* streamHandle); + + /** + * Sets the resample ratio + * @note This function may return false if the stream is not resampling, if you wish to use this be sure to set the AESTREAM_FORCE_RESAMPLE option + * @param[in] ratio the new sample rate ratio, calculated by ((double)desiredRate / (double)GetSampleRate()) + */ + static void aestream_set_resample_ratio(void* kodiBase, + AEStreamHandle* streamHandle, + double ratio); +}; + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/CMakeLists.txt b/xbmc/addons/interfaces/CMakeLists.txt new file mode 100644 index 0000000..8e58bb6 --- /dev/null +++ b/xbmc/addons/interfaces/CMakeLists.txt @@ -0,0 +1,18 @@ +set(SOURCES AddonBase.cpp + AudioEngine.cpp + General.cpp + Filesystem.cpp + Network.cpp) + +set(HEADERS AddonBase.h + AudioEngine.h + General.h + Filesystem.h + Network.h) + +if(CORE_SYSTEM_NAME STREQUAL android) + list(APPEND SOURCES platform/android/System.cpp) + list(APPEND HEADERS platform/android/System.h) +endif() + +core_add_library(addons_interfaces) diff --git a/xbmc/addons/interfaces/Filesystem.cpp b/xbmc/addons/interfaces/Filesystem.cpp new file mode 100644 index 0000000..c063b48 --- /dev/null +++ b/xbmc/addons/interfaces/Filesystem.cpp @@ -0,0 +1,1181 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Filesystem.h" + +#include "FileItem.h" +#include "Util.h" +#include "addons/binary-addons/AddonDll.h" +#include "filesystem/CurlFile.h" +#include "filesystem/Directory.h" +#include "filesystem/File.h" +#include "filesystem/SpecialProtocol.h" +#include "platform/Filesystem.h" +#include "utils/Crc32.h" +#include "utils/HttpHeader.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +#include <vector> + +#if defined(TARGET_WINDOWS) +#ifndef S_IFLNK +#define S_IFLNK 0120000 +#endif +#ifndef S_ISBLK +#define S_ISBLK(m) (0) +#endif +#ifndef S_ISSOCK +#define S_ISSOCK(m) (0) +#endif +#ifndef S_ISLNK +#define S_ISLNK(m) ((m & S_IFLNK) != 0) +#endif +#ifndef S_ISCHR +#define S_ISCHR(m) ((m & _S_IFCHR) != 0) +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) ((m & _S_IFDIR) != 0) +#endif +#ifndef S_ISFIFO +#define S_ISFIFO(m) ((m & _S_IFIFO) != 0) +#endif +#ifndef S_ISREG +#define S_ISREG(m) ((m & _S_IFREG) != 0) +#endif +#endif + +using namespace kodi; // addon-dev-kit namespace +using namespace XFILE; + +extern "C" +{ +namespace ADDON +{ + +void Interface_Filesystem::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_filesystem = new AddonToKodiFuncTable_kodi_filesystem(); + + addonInterface->toKodi->kodi_filesystem->can_open_directory = can_open_directory; + addonInterface->toKodi->kodi_filesystem->create_directory = create_directory; + addonInterface->toKodi->kodi_filesystem->directory_exists = directory_exists; + addonInterface->toKodi->kodi_filesystem->remove_directory = remove_directory; + addonInterface->toKodi->kodi_filesystem->remove_directory_recursive = remove_directory_recursive; + addonInterface->toKodi->kodi_filesystem->get_directory = get_directory; + addonInterface->toKodi->kodi_filesystem->free_directory = free_directory; + + addonInterface->toKodi->kodi_filesystem->file_exists = file_exists; + addonInterface->toKodi->kodi_filesystem->stat_file = stat_file; + addonInterface->toKodi->kodi_filesystem->delete_file = delete_file; + addonInterface->toKodi->kodi_filesystem->rename_file = rename_file; + addonInterface->toKodi->kodi_filesystem->copy_file = copy_file; + addonInterface->toKodi->kodi_filesystem->get_file_md5 = get_file_md5; + addonInterface->toKodi->kodi_filesystem->get_cache_thumb_name = get_cache_thumb_name; + addonInterface->toKodi->kodi_filesystem->make_legal_filename = make_legal_filename; + addonInterface->toKodi->kodi_filesystem->make_legal_path = make_legal_path; + addonInterface->toKodi->kodi_filesystem->translate_special_protocol = translate_special_protocol; + addonInterface->toKodi->kodi_filesystem->get_disk_space = get_disk_space; + addonInterface->toKodi->kodi_filesystem->is_internet_stream = is_internet_stream; + addonInterface->toKodi->kodi_filesystem->is_on_lan = is_on_lan; + addonInterface->toKodi->kodi_filesystem->is_remote = is_remote; + addonInterface->toKodi->kodi_filesystem->is_local = is_local; + addonInterface->toKodi->kodi_filesystem->is_url = is_url; + addonInterface->toKodi->kodi_filesystem->get_http_header = get_http_header; + addonInterface->toKodi->kodi_filesystem->get_mime_type = get_mime_type; + addonInterface->toKodi->kodi_filesystem->get_content_type = get_content_type; + addonInterface->toKodi->kodi_filesystem->get_cookies = get_cookies; + + addonInterface->toKodi->kodi_filesystem->http_header_create = http_header_create; + addonInterface->toKodi->kodi_filesystem->http_header_free = http_header_free; + + addonInterface->toKodi->kodi_filesystem->open_file = open_file; + addonInterface->toKodi->kodi_filesystem->open_file_for_write = open_file_for_write; + addonInterface->toKodi->kodi_filesystem->read_file = read_file; + addonInterface->toKodi->kodi_filesystem->read_file_string = read_file_string; + addonInterface->toKodi->kodi_filesystem->write_file = write_file; + addonInterface->toKodi->kodi_filesystem->flush_file = flush_file; + addonInterface->toKodi->kodi_filesystem->seek_file = seek_file; + addonInterface->toKodi->kodi_filesystem->truncate_file = truncate_file; + addonInterface->toKodi->kodi_filesystem->get_file_position = get_file_position; + addonInterface->toKodi->kodi_filesystem->get_file_length = get_file_length; + addonInterface->toKodi->kodi_filesystem->get_file_download_speed = get_file_download_speed; + addonInterface->toKodi->kodi_filesystem->close_file = close_file; + addonInterface->toKodi->kodi_filesystem->get_file_chunk_size = get_file_chunk_size; + addonInterface->toKodi->kodi_filesystem->io_control_get_seek_possible = + io_control_get_seek_possible; + addonInterface->toKodi->kodi_filesystem->io_control_get_cache_status = + io_control_get_cache_status; + addonInterface->toKodi->kodi_filesystem->io_control_set_cache_rate = io_control_set_cache_rate; + addonInterface->toKodi->kodi_filesystem->io_control_set_retry = io_control_set_retry; + addonInterface->toKodi->kodi_filesystem->get_property_values = get_property_values; + + addonInterface->toKodi->kodi_filesystem->curl_create = curl_create; + addonInterface->toKodi->kodi_filesystem->curl_add_option = curl_add_option; + addonInterface->toKodi->kodi_filesystem->curl_open = curl_open; +} + +void Interface_Filesystem::DeInit(AddonGlobalInterface* addonInterface) +{ + if (addonInterface->toKodi) /* <-- Safe check, needed so long old addon way is present */ + { + delete addonInterface->toKodi->kodi_filesystem; + addonInterface->toKodi->kodi_filesystem = nullptr; + } +} + +unsigned int Interface_Filesystem::TranslateFileReadBitsToKodi(unsigned int addonFlags) +{ + unsigned int kodiFlags = 0; + + if (addonFlags & ADDON_READ_TRUNCATED) + kodiFlags |= READ_TRUNCATED; + if (addonFlags & ADDON_READ_CHUNKED) + kodiFlags |= READ_CHUNKED; + if (addonFlags & ADDON_READ_CACHED) + kodiFlags |= READ_CACHED; + if (addonFlags & ADDON_READ_NO_CACHE) + kodiFlags |= READ_NO_CACHE; + if (addonFlags & ADDON_READ_BITRATE) + kodiFlags |= READ_BITRATE; + if (addonFlags & ADDON_READ_MULTI_STREAM) + kodiFlags |= READ_MULTI_STREAM; + if (addonFlags & ADDON_READ_AUDIO_VIDEO) + kodiFlags |= READ_AUDIO_VIDEO; + if (addonFlags & ADDON_READ_AFTER_WRITE) + kodiFlags |= READ_AFTER_WRITE; + if (addonFlags & READ_REOPEN) + kodiFlags |= READ_REOPEN; + + return kodiFlags; +} + +bool Interface_Filesystem::can_open_directory(void* kodiBase, const char* url) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', url='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(url)); + return false; + } + + CFileItemList items; + return CDirectory::GetDirectory(url, items, "", DIR_FLAG_DEFAULTS | DIR_FLAG_BYPASS_CACHE); +} + +bool Interface_Filesystem::create_directory(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return CDirectory::Create(path); +} + +bool Interface_Filesystem::directory_exists(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return CDirectory::Exists(path, false); +} + +bool Interface_Filesystem::remove_directory(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + // Empty directory + CFileItemList fileItems; + CDirectory::GetDirectory(path, fileItems, "", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_BYPASS_CACHE); + for (int i = 0; i < fileItems.Size(); ++i) + CFile::Delete(fileItems.Get(i)->GetPath()); + + return CDirectory::Remove(path); +} + +bool Interface_Filesystem::remove_directory_recursive(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return CDirectory::RemoveRecursive(path); +} + +static void CFileItemListToVFSDirEntries(VFSDirEntry* entries, const CFileItemList& items) +{ + for (unsigned int i = 0; i < static_cast<unsigned int>(items.Size()); ++i) + { + entries[i].label = strdup(items[i]->GetLabel().c_str()); + entries[i].path = strdup(items[i]->GetPath().c_str()); + entries[i].size = items[i]->m_dwSize; + entries[i].folder = items[i]->m_bIsFolder; + items[i]->m_dateTime.GetAsTime(entries[i].date_time); + } +} + +bool Interface_Filesystem::get_directory(void* kodiBase, + const char* path, + const char* mask, + struct VFSDirEntry** items, + unsigned int* num_items) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr || mask == nullptr || items == nullptr || + num_items == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', path='{}', mask='{}', " + "items='{}', num_items='{}'", + __FUNCTION__, kodiBase, static_cast<const void*>(path), + static_cast<const void*>(mask), static_cast<void*>(items), + static_cast<void*>(num_items)); + return false; + } + + CFileItemList fileItems; + if (!CDirectory::GetDirectory(path, fileItems, mask, + DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_BYPASS_CACHE)) + return false; + + if (fileItems.Size() > 0) + { + *num_items = static_cast<unsigned int>(fileItems.Size()); + *items = new VFSDirEntry[fileItems.Size()]; + CFileItemListToVFSDirEntries(*items, fileItems); + } + else + { + *num_items = 0; + *items = nullptr; + } + + return true; +} + +void Interface_Filesystem::free_directory(void* kodiBase, + struct VFSDirEntry* items, + unsigned int num_items) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || items == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', items='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(items)); + return; + } + + for (unsigned int i = 0; i < num_items; ++i) + { + free(items[i].label); + free(items[i].path); + } + delete[] items; +} + +//------------------------------------------------------------------------------ + +bool Interface_Filesystem::file_exists(void* kodiBase, const char* filename, bool useCache) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(filename)); + return false; + } + + return CFile::Exists(filename, useCache); +} + +bool Interface_Filesystem::stat_file(void* kodiBase, + const char* filename, + struct STAT_STRUCTURE* buffer) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr || buffer == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}', buffer='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(filename), + static_cast<void*>(buffer)); + return false; + } + + struct __stat64 statBuffer; + if (CFile::Stat(filename, &statBuffer) != 0) + return false; + + buffer->deviceId = statBuffer.st_dev; + buffer->fileSerialNumber = statBuffer.st_ino; + buffer->size = statBuffer.st_size; + buffer->accessTime = statBuffer.st_atime; + buffer->modificationTime = statBuffer.st_mtime; + buffer->statusTime = statBuffer.st_ctime; + buffer->isDirectory = S_ISDIR(statBuffer.st_mode); + buffer->isSymLink = S_ISLNK(statBuffer.st_mode); + buffer->isBlock = S_ISBLK(statBuffer.st_mode); + buffer->isCharacter = S_ISCHR(statBuffer.st_mode); + buffer->isFifo = S_ISFIFO(statBuffer.st_mode); + buffer->isRegular = S_ISREG(statBuffer.st_mode); + buffer->isSocket = S_ISSOCK(statBuffer.st_mode); + + return true; +} + +bool Interface_Filesystem::delete_file(void* kodiBase, const char* filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(filename)); + return false; + } + + return CFile::Delete(filename); +} + +bool Interface_Filesystem::rename_file(void* kodiBase, + const char* filename, + const char* newFileName) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr || newFileName == nullptr) + { + CLog::Log( + LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}', newFileName='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(filename), + static_cast<const void*>(newFileName)); + return false; + } + + return CFile::Rename(filename, newFileName); +} + +bool Interface_Filesystem::copy_file(void* kodiBase, const char* filename, const char* dest) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr || dest == nullptr) + { + CLog::Log( + LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}', dest='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(filename), static_cast<const void*>(dest)); + return false; + } + + return CFile::Copy(filename, dest); +} + +char* Interface_Filesystem::get_file_md5(void* kodiBase, const char* filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(filename)); + return nullptr; + } + + std::string string = CUtil::GetFileDigest(filename, KODI::UTILITY::CDigest::Type::MD5); + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::get_cache_thumb_name(void* kodiBase, const char* filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(filename)); + return nullptr; + } + + const auto crc = Crc32::ComputeFromLowerCase(filename); + const auto hex = StringUtils::Format("{:08x}.tbn", crc); + char* buffer = strdup(hex.c_str()); + return buffer; +} + +char* Interface_Filesystem::make_legal_filename(void* kodiBase, const char* filename) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(filename)); + return nullptr; + } + + std::string string = CUtil::MakeLegalFileName(filename); + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::make_legal_path(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return nullptr; + } + + std::string string = CUtil::MakeLegalPath(path); + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::translate_special_protocol(void* kodiBase, const char* strSource) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || strSource == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', strSource='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(strSource)); + return nullptr; + } + + return strdup(CSpecialProtocol::TranslatePath(strSource).c_str()); +} + +bool Interface_Filesystem::get_disk_space( + void* kodiBase, const char* path, uint64_t* capacity, uint64_t* free, uint64_t* available) +{ + using namespace KODI::PLATFORM::FILESYSTEM; + + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr || capacity == nullptr || free == nullptr || + available == nullptr) + { + CLog::Log( + LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', path='{}, capacity='{}, free='{}, " + "available='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(path), static_cast<void*>(capacity), + static_cast<void*>(free), static_cast<void*>(available)); + return false; + } + + std::error_code ec; + auto freeSpace = space(CSpecialProtocol::TranslatePath(path), ec); + if (ec.value() != 0) + return false; + + *capacity = freeSpace.capacity; + *free = freeSpace.free; + *available = freeSpace.available; + return true; +} + +bool Interface_Filesystem::is_internet_stream(void* kodiBase, const char* path, bool strictCheck) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return URIUtils::IsInternetStream(path, strictCheck); +} + +bool Interface_Filesystem::is_on_lan(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return URIUtils::IsOnLAN(path); +} + +bool Interface_Filesystem::is_remote(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return URIUtils::IsRemote(path); +} + +bool Interface_Filesystem::is_local(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return CURL(path).IsLocal(); +} + +bool Interface_Filesystem::is_url(void* kodiBase, const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || path == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', path='{})", + __FUNCTION__, kodiBase, static_cast<const void*>(path)); + return false; + } + + return URIUtils::IsURL(path); +} + +bool Interface_Filesystem::get_mime_type(void* kodiBase, + const char* url, + char** content, + const char* useragent) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr || content == nullptr || useragent == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', url='{}', content='{}', " + "useragent='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(url), + static_cast<const void*>(content), static_cast<const void*>(useragent)); + return false; + } + + std::string kodiContent; + bool ret = XFILE::CCurlFile::GetMimeType(CURL(url), kodiContent, useragent); + if (ret && !kodiContent.empty()) + { + *content = strdup(kodiContent.c_str()); + } + return ret; +} + +bool Interface_Filesystem::get_content_type(void* kodiBase, + const char* url, + char** content, + const char* useragent) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr || content == nullptr || useragent == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', url='{}', content='{}', " + "useragent='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(url), + static_cast<const void*>(content), static_cast<const void*>(useragent)); + return false; + } + + std::string kodiContent; + bool ret = XFILE::CCurlFile::GetContentType(CURL(url), kodiContent, useragent); + if (ret && !kodiContent.empty()) + { + *content = strdup(kodiContent.c_str()); + } + return ret; +} + +bool Interface_Filesystem::get_cookies(void* kodiBase, const char* url, char** cookies) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr || cookies == nullptr) + { + CLog::Log( + LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', url='{}', cookies='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(url), static_cast<const void*>(cookies)); + return false; + } + + std::string kodiCookies; + bool ret = XFILE::CCurlFile::GetCookies(CURL(url), kodiCookies); + if (ret && !kodiCookies.empty()) + { + *cookies = strdup(kodiCookies.c_str()); + } + return ret; +} + +bool Interface_Filesystem::get_http_header(void* kodiBase, + const char* url, + struct KODI_HTTP_HEADER* headers) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr || headers == nullptr || headers->handle == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data pointer given", __func__); + return false; + } + + CHttpHeader* httpHeader = static_cast<CHttpHeader*>(headers->handle); + return XFILE::CCurlFile::GetHttpHeader(CURL(url), *httpHeader); +} + +//------------------------------------------------------------------------------ + +bool Interface_Filesystem::http_header_create(void* kodiBase, struct KODI_HTTP_HEADER* headers) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || headers == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', headers='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(headers)); + return false; + } + + headers->handle = new CHttpHeader; + headers->get_value = http_header_get_value; + headers->get_values = http_header_get_values; + headers->get_header = http_header_get_header; + headers->get_mime_type = http_header_get_mime_type; + headers->get_charset = http_header_get_charset; + headers->get_proto_line = http_header_get_proto_line; + + return true; +} + +void Interface_Filesystem::http_header_free(void* kodiBase, struct KODI_HTTP_HEADER* headers) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || headers == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', headers='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(headers)); + return; + } + + delete static_cast<CHttpHeader*>(headers->handle); + headers->handle = nullptr; +} + +char* Interface_Filesystem::http_header_get_value(void* kodiBase, void* handle, const char* param) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || handle == nullptr || param == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}', param='{}')", + __FUNCTION__, kodiBase, handle, static_cast<const void*>(param)); + return nullptr; + } + + std::string string = static_cast<CHttpHeader*>(handle)->GetValue(param); + + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +char** Interface_Filesystem::http_header_get_values(void* kodiBase, + void* handle, + const char* param, + int* length) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || handle == nullptr || param == nullptr || length == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}', param='{}', " + "length='{}')", + __FUNCTION__, kodiBase, handle, static_cast<const void*>(param), + static_cast<const void*>(length)); + return nullptr; + } + + + std::vector<std::string> values = static_cast<CHttpHeader*>(handle)->GetValues(param); + *length = values.size(); + char** ret = static_cast<char**>(malloc(sizeof(char*) * values.size())); + for (int i = 0; i < *length; ++i) + { + ret[i] = strdup(values[i].c_str()); + } + return ret; +} + +char* Interface_Filesystem::http_header_get_header(void* kodiBase, void* handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || handle == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')", + __FUNCTION__, kodiBase, handle); + return nullptr; + } + + std::string string = static_cast<CHttpHeader*>(handle)->GetHeader(); + + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::http_header_get_mime_type(void* kodiBase, void* handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || handle == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')", + __FUNCTION__, kodiBase, handle); + return nullptr; + } + + std::string string = static_cast<CHttpHeader*>(handle)->GetMimeType(); + + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::http_header_get_charset(void* kodiBase, void* handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || handle == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')", + __FUNCTION__, kodiBase, handle); + return nullptr; + } + + std::string string = static_cast<CHttpHeader*>(handle)->GetCharset(); + + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Filesystem::http_header_get_proto_line(void* kodiBase, void* handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || handle == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', handle='{}')", + __FUNCTION__, kodiBase, handle); + return nullptr; + } + + std::string string = static_cast<CHttpHeader*>(handle)->GetProtoLine(); + + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +//------------------------------------------------------------------------------ + +void* Interface_Filesystem::open_file(void* kodiBase, const char* filename, unsigned int flags) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(filename)); + return nullptr; + } + + CFile* file = new CFile; + if (file->Open(filename, TranslateFileReadBitsToKodi(flags))) + return static_cast<void*>(file); + + delete file; + return nullptr; +} + +void* Interface_Filesystem::open_file_for_write(void* kodiBase, + const char* filename, + bool overwrite) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || filename == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', filename='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(filename)); + return nullptr; + } + + CFile* file = new CFile; + if (file->OpenForWrite(filename, overwrite)) + return static_cast<void*>(file); + + delete file; + return nullptr; +} + +ssize_t Interface_Filesystem::read_file(void* kodiBase, void* file, void* ptr, size_t size) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || ptr == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}', ptr='{}')", + __FUNCTION__, kodiBase, file, ptr); + return -1; + } + + return static_cast<CFile*>(file)->Read(ptr, size); +} + +bool Interface_Filesystem::read_file_string(void* kodiBase, + void* file, + char* szLine, + int lineLength) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || szLine == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', file='{}', szLine=='{}')", + __FUNCTION__, kodiBase, file, static_cast<void*>(szLine)); + return false; + } + + return static_cast<CFile*>(file)->ReadString(szLine, lineLength); +} + +ssize_t Interface_Filesystem::write_file(void* kodiBase, void* file, const void* ptr, size_t size) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || ptr == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}', ptr='{}')", + __FUNCTION__, kodiBase, file, ptr); + return -1; + } + + return static_cast<CFile*>(file)->Write(ptr, size); +} + +void Interface_Filesystem::flush_file(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return; + } + + static_cast<CFile*>(file)->Flush(); +} + +int64_t Interface_Filesystem::seek_file(void* kodiBase, void* file, int64_t position, int whence) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return -1; + } + + return static_cast<CFile*>(file)->Seek(position, whence); +} + +int Interface_Filesystem::truncate_file(void* kodiBase, void* file, int64_t size) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return -1; + } + + return static_cast<CFile*>(file)->Truncate(size); +} + +int64_t Interface_Filesystem::get_file_position(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return -1; + } + + return static_cast<CFile*>(file)->GetPosition(); +} + +int64_t Interface_Filesystem::get_file_length(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return -1; + } + + return static_cast<CFile*>(file)->GetLength(); +} + +double Interface_Filesystem::get_file_download_speed(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return 0.0; + } + + return static_cast<CFile*>(file)->GetDownloadSpeed(); +} + +void Interface_Filesystem::close_file(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return; + } + + static_cast<CFile*>(file)->Close(); + delete static_cast<CFile*>(file); +} + +int Interface_Filesystem::get_file_chunk_size(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}')", __FUNCTION__, + kodiBase, file); + return -1; + } + + return static_cast<CFile*>(file)->GetChunkSize(); +} + +bool Interface_Filesystem::io_control_get_seek_possible(void* kodiBase, void* file) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}')", __FUNCTION__, + kodiBase, file); + return false; + } + + return static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_SEEK_POSSIBLE, nullptr) != 0 + ? true + : false; +} + +bool Interface_Filesystem::io_control_get_cache_status(void* kodiBase, + void* file, + struct VFS_CACHE_STATUS_DATA* status) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || status == nullptr) + { + CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}, status='{}')", + __FUNCTION__, kodiBase, file, static_cast<const void*>(status)); + return false; + } + + SCacheStatus data = {}; + int ret = static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_CACHE_STATUS, &data); + if (ret >= 0) + { + status->forward = data.forward; + status->maxrate = data.maxrate; + status->currate = data.currate; + status->lowrate = data.lowrate; + return true; + } + return false; +} + +bool Interface_Filesystem::io_control_set_cache_rate(void* kodiBase, void* file, uint32_t rate) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}')", __FUNCTION__, + kodiBase, file); + return false; + } + + return static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_CACHE_SETRATE, &rate) >= 0 ? true + : false; +} + +bool Interface_Filesystem::io_control_set_retry(void* kodiBase, void* file, bool retry) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_VFS::{} - invalid data (addon='{}', file='{}')", __FUNCTION__, + kodiBase, file); + return false; + } + + return static_cast<CFile*>(file)->IoControl(EIoControl::IOCTRL_SET_RETRY, &retry) >= 0 ? true + : false; +} + +char** Interface_Filesystem::get_property_values( + void* kodiBase, void* file, int type, const char* name, int* numValues) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || name == nullptr || numValues == nullptr) + { + CLog::Log(LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', file='{}', name='{}', " + "numValues='{}')", + __FUNCTION__, kodiBase, file, static_cast<const void*>(name), + static_cast<void*>(numValues)); + return nullptr; + } + + XFILE::FileProperty internalType; + switch (type) + { + case ADDON_FILE_PROPERTY_RESPONSE_PROTOCOL: + internalType = XFILE::FILE_PROPERTY_RESPONSE_PROTOCOL; + break; + case ADDON_FILE_PROPERTY_RESPONSE_HEADER: + internalType = XFILE::FILE_PROPERTY_RESPONSE_HEADER; + break; + case ADDON_FILE_PROPERTY_CONTENT_TYPE: + internalType = XFILE::FILE_PROPERTY_CONTENT_TYPE; + break; + case ADDON_FILE_PROPERTY_CONTENT_CHARSET: + internalType = XFILE::FILE_PROPERTY_CONTENT_CHARSET; + break; + case ADDON_FILE_PROPERTY_MIME_TYPE: + internalType = XFILE::FILE_PROPERTY_MIME_TYPE; + break; + case ADDON_FILE_PROPERTY_EFFECTIVE_URL: + internalType = XFILE::FILE_PROPERTY_EFFECTIVE_URL; + break; + default: + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return nullptr; + }; + std::vector<std::string> values = + static_cast<CFile*>(file)->GetPropertyValues(internalType, name); + *numValues = values.size(); + char** ret = static_cast<char**>(malloc(sizeof(char*) * values.size())); + for (int i = 0; i < *numValues; ++i) + { + ret[i] = strdup(values[i].c_str()); + } + return ret; +} + +void* Interface_Filesystem::curl_create(void* kodiBase, const char* url) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', url='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(url)); + return nullptr; + } + + CFile* file = new CFile; + if (file->CURLCreate(url)) + return static_cast<void*>(file); + + delete file; + return nullptr; +} + +bool Interface_Filesystem::curl_add_option( + void* kodiBase, void* file, int type, const char* name, const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr || name == nullptr || value == nullptr) + { + CLog::Log( + LOGERROR, + "Interface_Filesystem::{} - invalid data (addon='{}', file='{}', name='{}', value='{}')", + __FUNCTION__, kodiBase, file, static_cast<const void*>(name), + static_cast<const void*>(value)); + return false; + } + + XFILE::CURLOPTIONTYPE internalType; + switch (type) + { + case ADDON_CURL_OPTION_OPTION: + internalType = XFILE::CURL_OPTION_OPTION; + break; + case ADDON_CURL_OPTION_PROTOCOL: + internalType = XFILE::CURL_OPTION_PROTOCOL; + break; + case ADDON_CURL_OPTION_CREDENTIALS: + internalType = XFILE::CURL_OPTION_CREDENTIALS; + break; + case ADDON_CURL_OPTION_HEADER: + internalType = XFILE::CURL_OPTION_HEADER; + break; + default: + throw std::logic_error("Interface_Filesystem::curl_add_option - invalid curl option type"); + return false; + }; + + return static_cast<CFile*>(file)->CURLAddOption(internalType, name, value); +} + +bool Interface_Filesystem::curl_open(void* kodiBase, void* file, unsigned int flags) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || file == nullptr) + { + CLog::Log(LOGERROR, "Interface_Filesystem::{} - invalid data (addon='{}', file='{}')", + __FUNCTION__, kodiBase, file); + return false; + } + + return static_cast<CFile*>(file)->CURLOpen(TranslateFileReadBitsToKodi(flags)); +} + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/Filesystem.h b/xbmc/addons/interfaces/Filesystem.h new file mode 100644 index 0000000..55e90ce --- /dev/null +++ b/xbmc/addons/interfaces/Filesystem.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/Filesystem.h" + +extern "C" +{ + +struct VFSDirEntry; +struct AddonGlobalInterface; + +namespace ADDON +{ + +struct Interface_Filesystem +{ + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + static unsigned int TranslateFileReadBitsToKodi(unsigned int addonFlags); + + /*! + * @brief callback functions from add-on to kodi + * + * @note For add of new functions use the "_" style to identify direct a + * add-on callback function. Everything with CamelCase is only for the + * usage in Kodi only. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + ///@{ + static bool can_open_directory(void* kodiBase, const char* url); + static bool create_directory(void* kodiBase, const char* path); + static bool directory_exists(void* kodiBase, const char* path); + static bool remove_directory(void* kodiBase, const char* path); + static bool remove_directory_recursive(void* kodiBase, const char* path); + static bool get_directory(void* kodiBase, + const char* path, + const char* mask, + struct VFSDirEntry** items, + unsigned int* num_items); + static void free_directory(void* kodiBase, struct VFSDirEntry* items, unsigned int num_items); + + static bool file_exists(void* kodiBase, const char* filename, bool useCache); + static bool stat_file(void* kodiBase, const char* filename, struct STAT_STRUCTURE* buffer); + static bool delete_file(void* kodiBase, const char* filename); + static bool rename_file(void* kodiBase, const char* filename, const char* newFileName); + static bool copy_file(void* kodiBase, const char* filename, const char* dest); + static char* get_file_md5(void* kodiBase, const char* filename); + static char* get_cache_thumb_name(void* kodiBase, const char* filename); + static char* make_legal_filename(void* kodiBase, const char* filename); + static char* make_legal_path(void* kodiBase, const char* path); + static char* translate_special_protocol(void* kodiBase, const char* strSource); + static bool get_disk_space( + void* kodiBase, const char* path, uint64_t* capacity, uint64_t* free, uint64_t* available); + static bool is_internet_stream(void* kodiBase, const char* path, bool strictCheck); + static bool is_on_lan(void* kodiBase, const char* path); + static bool is_remote(void* kodiBase, const char* path); + static bool is_local(void* kodiBase, const char* path); + static bool is_url(void* kodiBase, const char* path); + + static bool get_http_header(void* kodiBase, const char* url, struct KODI_HTTP_HEADER* headers); + static bool get_mime_type(void* kodiBase, const char* url, char** content, const char* useragent); + static bool get_content_type(void* kodiBase, + const char* url, + char** content, + const char* useragent); + static bool get_cookies(void* kodiBase, const char* url, char** cookies); + + /*! + * @brief Callback functions addon class kodi::vfs::CFile + */ + ///@{ + static bool http_header_create(void* kodiBase, struct KODI_HTTP_HEADER* headers); + static void http_header_free(void* kodiBase, struct KODI_HTTP_HEADER* headers); + + static char* http_header_get_value(void* kodiBase, void* handle, const char* param); + static char** http_header_get_values(void* kodiBase, + void* handle, + const char* param, + int* length); + static char* http_header_get_header(void* kodiBase, void* handle); + static char* http_header_get_mime_type(void* kodiBase, void* handle); + static char* http_header_get_charset(void* kodiBase, void* handle); + static char* http_header_get_proto_line(void* kodiBase, void* handle); + ///@} + + /*! + * @brief Callback functions addon class kodi::vfs::CFile + */ + ///@{ + static void* open_file(void* kodiBase, const char* filename, unsigned int flags); + static void* open_file_for_write(void* kodiBase, const char* filename, bool overwrite); + static ssize_t read_file(void* kodiBase, void* file, void* ptr, size_t size); + static bool read_file_string(void* kodiBase, void* file, char* szLine, int lineLength); + static ssize_t write_file(void* kodiBase, void* file, const void* ptr, size_t size); + static void flush_file(void* kodiBase, void* file); + static int64_t seek_file(void* kodiBase, void* file, int64_t position, int whence); + static int truncate_file(void* kodiBase, void* file, int64_t size); + static int64_t get_file_position(void* kodiBase, void* file); + static int64_t get_file_length(void* kodiBase, void* file); + static double get_file_download_speed(void* kodiBase, void* file); + static void close_file(void* kodiBase, void* file); + static int get_file_chunk_size(void* kodiBase, void* file); + static bool io_control_get_seek_possible(void* kodiBase, void* file); + static bool io_control_get_cache_status(void* kodiBase, + void* file, + struct VFS_CACHE_STATUS_DATA* status); + static bool io_control_set_cache_rate(void* kodiBase, void* file, uint32_t rate); + static bool io_control_set_retry(void* kodiBase, void* file, bool retry); + static char** get_property_values( + void* kodiBase, void* file, int type, const char* name, int* numValues); + + static void* curl_create(void* kodiBase, const char* url); + static bool curl_add_option( + void* kodiBase, void* file, int type, const char* name, const char* value); + static bool curl_open(void* kodiBase, void* file, unsigned int flags); + ///@} + ///@} +}; + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/General.cpp b/xbmc/addons/interfaces/General.cpp new file mode 100644 index 0000000..eef6ccd --- /dev/null +++ b/xbmc/addons/interfaces/General.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "General.h" + +#include "CompileInfo.h" +#include "LangInfo.h" +#include "ServiceBroker.h" +#include "addons/AddonManager.h" +#include "addons/AddonVersion.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/General.h" +#include "application/ApplicationComponents.h" +#include "application/ApplicationPowerHandling.h" +#include "dialogs/GUIDialogKaiToast.h" +#include "input/KeyboardLayout.h" +#include "input/KeyboardLayoutManager.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/CharsetConverter.h" +#include "utils/Digest.h" +#include "utils/LangCodeExpander.h" +#include "utils/MemUtils.h" +#include "utils/StringUtils.h" +#include "utils/log.h" + +#include <string.h> + +using namespace kodi; // addon-dev-kit namespace +using KODI::UTILITY::CDigest; + +namespace ADDON +{ + +void Interface_General::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi = static_cast<AddonToKodiFuncTable_kodi*>(malloc(sizeof(AddonToKodiFuncTable_kodi))); + + addonInterface->toKodi->kodi->unknown_to_utf8 = unknown_to_utf8; + addonInterface->toKodi->kodi->get_language = get_language; + addonInterface->toKodi->kodi->queue_notification = queue_notification; + addonInterface->toKodi->kodi->get_md5 = get_md5; + addonInterface->toKodi->kodi->get_region = get_region; + addonInterface->toKodi->kodi->get_free_mem = get_free_mem; + addonInterface->toKodi->kodi->get_global_idle_time = get_global_idle_time; + addonInterface->toKodi->kodi->is_addon_avilable = is_addon_avilable; + addonInterface->toKodi->kodi->kodi_version = kodi_version; + addonInterface->toKodi->kodi->get_current_skin_id = get_current_skin_id; + addonInterface->toKodi->kodi->get_keyboard_layout = get_keyboard_layout; + addonInterface->toKodi->kodi->change_keyboard_layout = change_keyboard_layout; +} + +void Interface_General::DeInit(AddonGlobalInterface* addonInterface) +{ + if (addonInterface->toKodi && /* <-- needed as long as the old addon way is used */ + addonInterface->toKodi->kodi) + { + free(addonInterface->toKodi->kodi); + addonInterface->toKodi->kodi = nullptr; + } +} + +char* Interface_General::unknown_to_utf8(void* kodiBase, const char* source, bool* ret, bool failOnBadChar) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon || !source || !ret) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}', source='{}', ret='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(source), static_cast<void*>(ret)); + return nullptr; + } + + std::string string; + *ret = g_charsetConverter.unknownToUTF8(source, string, failOnBadChar); + char* buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_General::get_language(void* kodiBase, int format, bool region) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}')", __FUNCTION__, + kodiBase); + return nullptr; + } + + std::string string = g_langInfo.GetEnglishLanguageName(); + switch (format) + { + case LANG_FMT_ISO_639_1: + { + std::string langCode; + g_LangCodeExpander.ConvertToISO6391(string, langCode); + string = langCode; + if (region) + { + std::string region2Code; + g_LangCodeExpander.ConvertToISO6391(g_langInfo.GetRegionLocale(), region2Code); + if (!region2Code.empty()) + string += "-" + region2Code; + } + break; + } + case LANG_FMT_ISO_639_2: + { + std::string langCode; + g_LangCodeExpander.ConvertToISO6392B(string, langCode); + string = langCode; + if (region) + { + std::string region3Code; + g_LangCodeExpander.ConvertToISO6392B(g_langInfo.GetRegionLocale(), region3Code); + if (!region3Code.empty()) + string += "-" + region3Code; + } + break; + } + case LANG_FMT_ENGLISH_NAME: + default: + { + if (region) + string += "-" + g_langInfo.GetCurrentRegion(); + break; + } + } + + char* buffer = strdup(string.c_str()); + return buffer; +} + +bool Interface_General::queue_notification(void* kodiBase, int type, const char* header, + const char* message, const char* imageFile, + unsigned int displayTime, bool withSound, + unsigned int messageTime) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || message == nullptr) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}', message='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(message)); + return false; + } + + std::string usedHeader; + if (header && strlen(header) > 0) + usedHeader = header; + else + usedHeader = addon->Name(); + + QueueMsg qtype = static_cast<QueueMsg>(type); + + if (qtype != QUEUE_OWN_STYLE) + { + CGUIDialogKaiToast::eMessageType usedType; + switch (qtype) + { + case QueueMsg::QUEUE_WARNING: + usedType = CGUIDialogKaiToast::Warning; + withSound = true; + CLog::Log(LOGDEBUG, "Interface_General::{} - {} - Warning Message: '{}'", __FUNCTION__, + addon->Name(), message); + break; + case QueueMsg::QUEUE_ERROR: + usedType = CGUIDialogKaiToast::Error; + withSound = true; + CLog::Log(LOGDEBUG, "Interface_General::{} - {} - Error Message : '{}'", __FUNCTION__, + addon->Name(), message); + break; + case QueueMsg::QUEUE_INFO: + default: + usedType = CGUIDialogKaiToast::Info; + withSound = false; + CLog::Log(LOGDEBUG, "Interface_General::{} - {} - Info Message : '{}'", __FUNCTION__, + addon->Name(), message); + break; + } + + if (imageFile && strlen(imageFile) > 0) + { + CLog::Log(LOGERROR, + "Interface_General::{} - To use given image file '{}' must be type value set to " + "'QUEUE_OWN_STYLE'", + __FUNCTION__, imageFile); + } + + CGUIDialogKaiToast::QueueNotification(usedType, usedHeader, message, 3000, withSound); + } + else + { + CGUIDialogKaiToast::QueueNotification(imageFile, usedHeader, message, displayTime, withSound, messageTime); + } + return true; +} + +void Interface_General::get_md5(void* kodiBase, const char* text, char* md5) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || text == nullptr) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}', text='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(text)); + return; + } + + std::string md5Int = CDigest::Calculate(CDigest::Type::MD5, std::string(text)); + strncpy(md5, md5Int.c_str(), 40); +} + +char* Interface_General::get_region(void* kodiBase, const char* id) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || id == nullptr) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}', id='{}')", __FUNCTION__, + kodiBase, static_cast<const void*>(id)); + return nullptr; + } + + std::string result; + if (StringUtils::CompareNoCase(id, "datelong") == 0) + { + result = g_langInfo.GetDateFormat(true); + StringUtils::Replace(result, "DDDD", "%A"); + StringUtils::Replace(result, "MMMM", "%B"); + StringUtils::Replace(result, "D", "%d"); + StringUtils::Replace(result, "YYYY", "%Y"); + } + else if (StringUtils::CompareNoCase(id, "dateshort") == 0) + { + result = g_langInfo.GetDateFormat(false); + StringUtils::Replace(result, "MM", "%m"); + StringUtils::Replace(result, "DD", "%d"); +#ifdef TARGET_WINDOWS + StringUtils::Replace(result, "M", "%#m"); + StringUtils::Replace(result, "D", "%#d"); +#else + StringUtils::Replace(result, "M", "%-m"); + StringUtils::Replace(result, "D", "%-d"); +#endif + StringUtils::Replace(result, "YYYY", "%Y"); + } + else if (StringUtils::CompareNoCase(id, "tempunit") == 0) + result = g_langInfo.GetTemperatureUnitString(); + else if (StringUtils::CompareNoCase(id, "speedunit") == 0) + result = g_langInfo.GetSpeedUnitString(); + else if (StringUtils::CompareNoCase(id, "time") == 0) + { + result = g_langInfo.GetTimeFormat(); + StringUtils::Replace(result, "H", "%H"); + StringUtils::Replace(result, "h", "%I"); + StringUtils::Replace(result, "mm", "%M"); + StringUtils::Replace(result, "ss", "%S"); + StringUtils::Replace(result, "xx", "%p"); + } + else if (StringUtils::CompareNoCase(id, "meridiem") == 0) + result = StringUtils::Format("{}/{}", g_langInfo.GetMeridiemSymbol(MeridiemSymbolAM), + g_langInfo.GetMeridiemSymbol(MeridiemSymbolPM)); + else + { + CLog::Log(LOGERROR, "Interface_General::{} - add-on '{}' requests invalid id '{}'", + __FUNCTION__, addon->Name(), id); + return nullptr; + } + + char* buffer = strdup(result.c_str()); + return buffer; +} + +void Interface_General::get_free_mem(void* kodiBase, long* free, long* total, bool as_bytes) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || free == nullptr || total == nullptr) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}', free='{}', total='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(free), static_cast<void*>(total)); + return; + } + + KODI::MEMORY::MemoryStatus stat; + KODI::MEMORY::GetMemoryStatus(&stat); + *free = static_cast<long>(stat.availPhys); + *total = static_cast<long>(stat.totalPhys); + if (!as_bytes) + { + *free = *free / ( 1024 * 1024 ); + *total = *total / ( 1024 * 1024 ); + } +} + +int Interface_General::get_global_idle_time(void* kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}')", __FUNCTION__, + kodiBase); + return -1; + } + + auto& components = CServiceBroker::GetAppComponents(); + const auto appPower = components.GetComponent<CApplicationPowerHandling>(); + return appPower->GlobalIdleTime(); +} + +bool Interface_General::is_addon_avilable(void* kodiBase, + const char* id, + char** version, + bool* enabled) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || id == nullptr || version == nullptr || enabled == nullptr) + { + CLog::Log( + LOGERROR, + "Interface_General::{} - invalid data (addon='{}', id='{}', version='{}', enabled='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(id), static_cast<void*>(version), + static_cast<void*>(enabled)); + return false; + } + + AddonPtr addonInfo; + if (!CServiceBroker::GetAddonMgr().GetAddon(id, addonInfo, OnlyEnabled::CHOICE_NO)) + return false; + + *version = strdup(addonInfo->Version().asString().c_str()); + *enabled = !CServiceBroker::GetAddonMgr().IsAddonDisabled(id); + return true; +} + +void Interface_General::kodi_version(void* kodiBase, char** compile_name, int* major, int* minor, char** revision, char** tag, char** tagversion) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || compile_name == nullptr || major == nullptr || minor == nullptr || + revision == nullptr || tag == nullptr || tagversion == nullptr) + { + CLog::Log(LOGERROR, + "Interface_General::{} - invalid data (addon='{}', compile_name='{}', major='{}', " + "minor='{}', revision='{}', tag='{}', tagversion='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(compile_name), static_cast<void*>(major), + static_cast<void*>(minor), static_cast<void*>(revision), static_cast<void*>(tag), + static_cast<void*>(tagversion)); + return; + } + + *compile_name = strdup(CCompileInfo::GetAppName()); + *major = CCompileInfo::GetMajor(); + *minor = CCompileInfo::GetMinor(); + *revision = strdup(CCompileInfo::GetSCMID()); + std::string tagStr = CCompileInfo::GetSuffix(); + if (StringUtils::StartsWithNoCase(tagStr, "alpha")) + { + *tag = strdup("alpha"); + *tagversion = strdup(StringUtils::Mid(tagStr, 5).c_str()); + } + else if (StringUtils::StartsWithNoCase(tagStr, "beta")) + { + *tag = strdup("beta"); + *tagversion = strdup(StringUtils::Mid(tagStr, 4).c_str()); + } + else if (StringUtils::StartsWithNoCase(tagStr, "rc")) + { + *tag = strdup("releasecandidate"); + *tagversion = strdup(StringUtils::Mid(tagStr, 2).c_str()); + } + else if (tagStr.empty()) + *tag = strdup("stable"); + else + *tag = strdup("prealpha"); +} + +char* Interface_General::get_current_skin_id(void* kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}')", __FUNCTION__, + kodiBase); + return nullptr; + } + + return strdup(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN).c_str()); +} + +bool Interface_General::get_keyboard_layout(void* kodiBase, char** layout_name, int modifier_key, AddonKeyboardKeyTable* c_layout) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || c_layout == nullptr || layout_name == nullptr) + { + CLog::Log(LOGERROR, + "Interface_General::{} - invalid data (addon='{}', c_layout='{}', layout_name='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(c_layout), + static_cast<void*>(layout_name)); + return false; + } + + std::string activeLayout = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT); + + CKeyboardLayout layout; + if (!CServiceBroker::GetKeyboardLayoutManager()->GetLayout(activeLayout, layout)) + return false; + + *layout_name = strdup(layout.GetName().c_str()); + + unsigned int modifiers = CKeyboardLayout::ModifierKeyNone; + if (modifier_key & STD_KB_MODIFIER_KEY_SHIFT) + modifiers |= CKeyboardLayout::ModifierKeyShift; + if (modifier_key & STD_KB_MODIFIER_KEY_SYMBOL) + modifiers |= CKeyboardLayout::ModifierKeySymbol; + + for (unsigned int row = 0; row < STD_KB_BUTTONS_MAX_ROWS; row++) + { + for (unsigned int column = 0; column < STD_KB_BUTTONS_PER_ROW; column++) + { + std::string label = layout.GetCharAt(row, column, modifiers); + c_layout->keys[row][column] = strdup(label.c_str()); + } + } + + return true; +} + +bool Interface_General::change_keyboard_layout(void* kodiBase, char** layout_name) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || layout_name == nullptr) + { + CLog::Log(LOGERROR, "Interface_General::{} - invalid data (addon='{}', layout_name='{}')", + __FUNCTION__, kodiBase, static_cast<void*>(layout_name)); + return false; + } + + std::vector<CKeyboardLayout> layouts; + unsigned int currentLayout = 0; + + const KeyboardLayouts& keyboardLayouts = CServiceBroker::GetKeyboardLayoutManager()->GetLayouts(); + const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings(); + std::vector<CVariant> layoutNames = settings->GetList(CSettings::SETTING_LOCALE_KEYBOARDLAYOUTS); + std::string activeLayout = settings->GetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT); + + for (const auto& layoutName : layoutNames) + { + const auto keyboardLayout = keyboardLayouts.find(layoutName.asString()); + if (keyboardLayout != keyboardLayouts.end()) + { + layouts.emplace_back(keyboardLayout->second); + if (layoutName.asString() == activeLayout) + currentLayout = layouts.size() - 1; + } + } + + currentLayout++; + if (currentLayout >= layouts.size()) + currentLayout = 0; + CKeyboardLayout layout = layouts.empty() ? CKeyboardLayout() : layouts[currentLayout]; + CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT, layout.GetName()); + + *layout_name = strdup(layout.GetName().c_str()); + return true; +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/General.h b/xbmc/addons/interfaces/General.h new file mode 100644 index 0000000..6dde356 --- /dev/null +++ b/xbmc/addons/interfaces/General.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +extern "C" +{ + +struct AddonGlobalInterface; +struct AddonKeyboardKeyTable; + +namespace ADDON +{ + +/*! + * @brief Global general Add-on to Kodi callback functions + * + * To hold general functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/General.h" + */ +struct Interface_General +{ + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static char* unknown_to_utf8(void* kodiBase, const char* source, bool* ret, bool failOnBadChar); + static char* get_language(void* kodiBase, int format, bool region); + static bool queue_notification(void* kodiBase, + int type, + const char* header, + const char* message, + const char* imageFile, + unsigned int displayTime, + bool withSound, + unsigned int messageTime); + static void get_md5(void* kodiBase, const char* text, char* md5); + static char* get_region(void* kodiBase, const char* id); + static void get_free_mem(void* kodiInstance, long* free, long* total, bool as_bytes); + static int get_global_idle_time(void* kodiBase); + static bool is_addon_avilable(void* kodiBase, const char* id, char** version, bool* enabled); + static void kodi_version(void* kodiBase, + char** compile_name, + int* major, + int* minor, + char** revision, + char** tag, + char** tagversion); + static char* get_current_skin_id(void* kodiBase); + static bool change_keyboard_layout(void* kodiBase, char** layout_name); + static bool get_keyboard_layout(void* kodiBase, + char** layout_name, + int modifier_key, + AddonKeyboardKeyTable* c_layout); + //@} +}; + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/Network.cpp b/xbmc/addons/interfaces/Network.cpp new file mode 100644 index 0000000..63151f3 --- /dev/null +++ b/xbmc/addons/interfaces/Network.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Network.h" + +#include "ServiceBroker.h" +#include "URL.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/Network.h" +#include "network/DNSNameCache.h" +#include "network/Network.h" +#include "utils/SystemInfo.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_Network::Init(AddonGlobalInterface *addonInterface) +{ + addonInterface->toKodi->kodi_network = new AddonToKodiFuncTable_kodi_network(); + + addonInterface->toKodi->kodi_network->wake_on_lan = wake_on_lan; + addonInterface->toKodi->kodi_network->get_ip_address = get_ip_address; + addonInterface->toKodi->kodi_network->get_hostname = get_hostname; + addonInterface->toKodi->kodi_network->get_user_agent = get_user_agent; + addonInterface->toKodi->kodi_network->is_local_host = is_local_host; + addonInterface->toKodi->kodi_network->is_host_on_lan = is_host_on_lan; + addonInterface->toKodi->kodi_network->dns_lookup = dns_lookup; + addonInterface->toKodi->kodi_network->url_encode = url_encode; +} + +void Interface_Network::DeInit(AddonGlobalInterface* addonInterface) +{ + if (addonInterface->toKodi) /* <-- needed as long as the old addon way is used */ + { + delete addonInterface->toKodi->kodi_network; + addonInterface->toKodi->kodi_network = nullptr; + } +} + +bool Interface_Network::wake_on_lan(void* kodiBase, const char* mac) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || mac == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}', mac='{}')", __FUNCTION__, + kodiBase, static_cast<const void*>(mac)); + return false; + } + + return CServiceBroker::GetNetwork().WakeOnLan(mac); +} + +char* Interface_Network::get_ip_address(void* kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}')", __FUNCTION__, + kodiBase); + return nullptr; + } + + std::string titleIP; + CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface(); + if (iface) + titleIP = iface->GetCurrentIPAddress(); + else + titleIP = "127.0.0.1"; + + char* buffer = nullptr; + if (!titleIP.empty()) + buffer = strdup(titleIP.c_str()); + return buffer; +} + +char* Interface_Network::get_hostname(void* kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}')", __FUNCTION__, + kodiBase); + return nullptr; + } + + std::string hostname; + if (!CServiceBroker::GetNetwork().GetHostName(hostname)) + return nullptr; + + char* buffer = nullptr; + if (!hostname.empty()) + buffer = strdup(hostname.c_str()); + return buffer; +} + +char* Interface_Network::get_user_agent(void* kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}')", __FUNCTION__, + kodiBase); + return nullptr; + } + + std::string string = CSysInfo::GetUserAgent(); + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +bool Interface_Network::is_local_host(void* kodiBase, const char* hostname) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || hostname == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}', hostname='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(hostname)); + return false; + } + + return CServiceBroker::GetNetwork().IsLocalHost(hostname); +} + +bool Interface_Network::is_host_on_lan(void* kodiBase, const char* hostname, bool offLineCheck) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || hostname == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}', hostname='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(hostname)); + return false; + } + + return URIUtils::IsHostOnLAN(hostname, offLineCheck); +} + +char* Interface_Network::dns_lookup(void* kodiBase, const char* url, bool* ret) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr || ret == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}', url='{}', ret='{}')", + __FUNCTION__, kodiBase, static_cast<const void*>(url), static_cast<void*>(ret)); + return nullptr; + } + + std::string string; + *ret = CDNSNameCache::Lookup(url, string); + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +char* Interface_Network::url_encode(void* kodiBase, const char* url) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (addon == nullptr || url == nullptr) + { + CLog::Log(LOGERROR, "Interface_Network::{} - invalid data (addon='{}', url='{}')", __FUNCTION__, + kodiBase, static_cast<const void*>(url)); + return nullptr; + } + + std::string string = CURL::Encode(url); + char* buffer = nullptr; + if (!string.empty()) + buffer = strdup(string.c_str()); + return buffer; +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/Network.h b/xbmc/addons/interfaces/Network.h new file mode 100644 index 0000000..b704fb1 --- /dev/null +++ b/xbmc/addons/interfaces/Network.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +struct AddonGlobalInterface; + +extern "C" +{ +namespace ADDON +{ + +/*! + * @brief Global general Add-on to Kodi callback functions + * + * To hold network functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/Network.h" + */ +struct Interface_Network +{ + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static bool wake_on_lan(void* kodiBase, const char* mac); + static char* get_ip_address(void* kodiBase); + static char* get_hostname(void* kodiBase); + static char* get_user_agent(void* kodiBase); + static bool is_local_host(void* kodiBase, const char* hostname); + static bool is_host_on_lan(void* kodiBase, const char* hostname, bool offLineCheck); + static char* dns_lookup(void* kodiBase, const char* url, bool* ret); + static char* url_encode(void* kodiBase, const char* url); + //@} +}; + +} /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/CMakeLists.txt b/xbmc/addons/interfaces/gui/CMakeLists.txt new file mode 100644 index 0000000..3508b82 --- /dev/null +++ b/xbmc/addons/interfaces/gui/CMakeLists.txt @@ -0,0 +1,11 @@ +set(SOURCES GUITranslator.cpp + General.cpp + ListItem.cpp + Window.cpp) + +set(HEADERS GUITranslator.h + General.h + ListItem.h + Window.h) + +core_add_library(addons_interfaces_gui) diff --git a/xbmc/addons/interfaces/gui/GUITranslator.cpp b/xbmc/addons/interfaces/gui/GUITranslator.cpp new file mode 100644 index 0000000..2db2601 --- /dev/null +++ b/xbmc/addons/interfaces/gui/GUITranslator.cpp @@ -0,0 +1,969 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "GUITranslator.h" + +#include "input/actions/ActionIDs.h" + +using namespace ADDON; + +ADDON_ACTION CAddonGUITranslator::TranslateActionIdToAddon(int kodiId) +{ + switch (kodiId) + { + case ACTION_NONE: + return ADDON_ACTION_NONE; + case ACTION_MOVE_LEFT: + return ADDON_ACTION_MOVE_LEFT; + case ACTION_MOVE_RIGHT: + return ADDON_ACTION_MOVE_RIGHT; + case ACTION_MOVE_UP: + return ADDON_ACTION_MOVE_UP; + case ACTION_MOVE_DOWN: + return ADDON_ACTION_MOVE_DOWN; + case ACTION_PAGE_UP: + return ADDON_ACTION_PAGE_UP; + case ACTION_PAGE_DOWN: + return ADDON_ACTION_PAGE_DOWN; + case ACTION_SELECT_ITEM: + return ADDON_ACTION_SELECT_ITEM; + case ACTION_HIGHLIGHT_ITEM: + return ADDON_ACTION_HIGHLIGHT_ITEM; + case ACTION_PARENT_DIR: + return ADDON_ACTION_PARENT_DIR; + case ACTION_PREVIOUS_MENU: + return ADDON_ACTION_PREVIOUS_MENU; + case ACTION_SHOW_INFO: + return ADDON_ACTION_SHOW_INFO; + case ACTION_PAUSE: + return ADDON_ACTION_PAUSE; + case ACTION_STOP: + return ADDON_ACTION_STOP; + case ACTION_NEXT_ITEM: + return ADDON_ACTION_NEXT_ITEM; + case ACTION_PREV_ITEM: + return ADDON_ACTION_PREV_ITEM; + case ACTION_FORWARD: + return ADDON_ACTION_FORWARD; + case ACTION_REWIND: + return ADDON_ACTION_REWIND; + case ACTION_SHOW_GUI: + return ADDON_ACTION_SHOW_GUI; + case ACTION_ASPECT_RATIO: + return ADDON_ACTION_ASPECT_RATIO; + case ACTION_STEP_FORWARD: + return ADDON_ACTION_STEP_FORWARD; + case ACTION_STEP_BACK: + return ADDON_ACTION_STEP_BACK; + case ACTION_BIG_STEP_FORWARD: + return ADDON_ACTION_BIG_STEP_FORWARD; + case ACTION_BIG_STEP_BACK: + return ADDON_ACTION_BIG_STEP_BACK; + case ACTION_SHOW_OSD: + return ADDON_ACTION_SHOW_OSD; + case ACTION_SHOW_SUBTITLES: + return ADDON_ACTION_SHOW_SUBTITLES; + case ACTION_NEXT_SUBTITLE: + return ADDON_ACTION_NEXT_SUBTITLE; + case ACTION_PLAYER_DEBUG: + return ADDON_ACTION_PLAYER_DEBUG; + case ACTION_NEXT_PICTURE: + return ADDON_ACTION_NEXT_PICTURE; + case ACTION_PREV_PICTURE: + return ADDON_ACTION_PREV_PICTURE; + case ACTION_ZOOM_OUT: + return ADDON_ACTION_ZOOM_OUT; + case ACTION_ZOOM_IN: + return ADDON_ACTION_ZOOM_IN; + case ACTION_TOGGLE_SOURCE_DEST: + return ADDON_ACTION_TOGGLE_SOURCE_DEST; + case ACTION_SHOW_PLAYLIST: + return ADDON_ACTION_SHOW_PLAYLIST; + case ACTION_QUEUE_ITEM: + return ADDON_ACTION_QUEUE_ITEM; + case ACTION_REMOVE_ITEM: + return ADDON_ACTION_REMOVE_ITEM; + case ACTION_SHOW_FULLSCREEN: + return ADDON_ACTION_SHOW_FULLSCREEN; + case ACTION_ZOOM_LEVEL_NORMAL: + return ADDON_ACTION_ZOOM_LEVEL_NORMAL; + case ACTION_ZOOM_LEVEL_1: + return ADDON_ACTION_ZOOM_LEVEL_1; + case ACTION_ZOOM_LEVEL_2: + return ADDON_ACTION_ZOOM_LEVEL_2; + case ACTION_ZOOM_LEVEL_3: + return ADDON_ACTION_ZOOM_LEVEL_3; + case ACTION_ZOOM_LEVEL_4: + return ADDON_ACTION_ZOOM_LEVEL_4; + case ACTION_ZOOM_LEVEL_5: + return ADDON_ACTION_ZOOM_LEVEL_5; + case ACTION_ZOOM_LEVEL_6: + return ADDON_ACTION_ZOOM_LEVEL_6; + case ACTION_ZOOM_LEVEL_7: + return ADDON_ACTION_ZOOM_LEVEL_7; + case ACTION_ZOOM_LEVEL_8: + return ADDON_ACTION_ZOOM_LEVEL_8; + case ACTION_ZOOM_LEVEL_9: + return ADDON_ACTION_ZOOM_LEVEL_9; + case ACTION_CALIBRATE_SWAP_ARROWS: + return ADDON_ACTION_CALIBRATE_SWAP_ARROWS; + case ACTION_CALIBRATE_RESET: + return ADDON_ACTION_CALIBRATE_RESET; + case ACTION_ANALOG_MOVE: + return ADDON_ACTION_ANALOG_MOVE; + case ACTION_ROTATE_PICTURE_CW: + return ADDON_ACTION_ROTATE_PICTURE_CW; + case ACTION_ROTATE_PICTURE_CCW: + return ADDON_ACTION_ROTATE_PICTURE_CCW; + case ACTION_SUBTITLE_DELAY_MIN: + return ADDON_ACTION_SUBTITLE_DELAY_MIN; + case ACTION_SUBTITLE_DELAY_PLUS: + return ADDON_ACTION_SUBTITLE_DELAY_PLUS; + case ACTION_AUDIO_DELAY_MIN: + return ADDON_ACTION_AUDIO_DELAY_MIN; + case ACTION_AUDIO_DELAY_PLUS: + return ADDON_ACTION_AUDIO_DELAY_PLUS; + case ACTION_AUDIO_NEXT_LANGUAGE: + return ADDON_ACTION_AUDIO_NEXT_LANGUAGE; + case ACTION_CHANGE_RESOLUTION: + return ADDON_ACTION_CHANGE_RESOLUTION; + case REMOTE_0: + return ADDON_ACTION_REMOTE_0; + case REMOTE_1: + return ADDON_ACTION_REMOTE_1; + case REMOTE_2: + return ADDON_ACTION_REMOTE_2; + case REMOTE_3: + return ADDON_ACTION_REMOTE_3; + case REMOTE_4: + return ADDON_ACTION_REMOTE_4; + case REMOTE_5: + return ADDON_ACTION_REMOTE_5; + case REMOTE_6: + return ADDON_ACTION_REMOTE_6; + case REMOTE_7: + return ADDON_ACTION_REMOTE_7; + case REMOTE_8: + return ADDON_ACTION_REMOTE_8; + case REMOTE_9: + return ADDON_ACTION_REMOTE_9; + case ACTION_PLAYER_PROCESS_INFO: + return ADDON_ACTION_PLAYER_PROCESS_INFO; + case ACTION_PLAYER_PROGRAM_SELECT: + return ADDON_ACTION_PLAYER_PROGRAM_SELECT; + case ACTION_PLAYER_RESOLUTION_SELECT: + return ADDON_ACTION_PLAYER_RESOLUTION_SELECT; + case ACTION_SMALL_STEP_BACK: + return ADDON_ACTION_SMALL_STEP_BACK; + case ACTION_PLAYER_FORWARD: + return ADDON_ACTION_PLAYER_FORWARD; + case ACTION_PLAYER_REWIND: + return ADDON_ACTION_PLAYER_REWIND; + case ACTION_PLAYER_PLAY: + return ADDON_ACTION_PLAYER_PLAY; + case ACTION_DELETE_ITEM: + return ADDON_ACTION_DELETE_ITEM; + case ACTION_COPY_ITEM: + return ADDON_ACTION_COPY_ITEM; + case ACTION_MOVE_ITEM: + return ADDON_ACTION_MOVE_ITEM; + case ACTION_TAKE_SCREENSHOT: + return ADDON_ACTION_TAKE_SCREENSHOT; + case ACTION_RENAME_ITEM: + return ADDON_ACTION_RENAME_ITEM; + case ACTION_VOLUME_UP: + return ADDON_ACTION_VOLUME_UP; + case ACTION_VOLUME_DOWN: + return ADDON_ACTION_VOLUME_DOWN; + case ACTION_VOLAMP: + return ADDON_ACTION_VOLAMP; + case ACTION_MUTE: + return ADDON_ACTION_MUTE; + case ACTION_NAV_BACK: + return ADDON_ACTION_NAV_BACK; + case ACTION_VOLAMP_UP: + return ADDON_ACTION_VOLAMP_UP; + case ACTION_VOLAMP_DOWN: + return ADDON_ACTION_VOLAMP_DOWN; + case ACTION_CREATE_EPISODE_BOOKMARK: + return ADDON_ACTION_CREATE_EPISODE_BOOKMARK; + case ACTION_CREATE_BOOKMARK: + return ADDON_ACTION_CREATE_BOOKMARK; + case ACTION_CHAPTER_OR_BIG_STEP_FORWARD: + return ADDON_ACTION_CHAPTER_OR_BIG_STEP_FORWARD; + case ACTION_CHAPTER_OR_BIG_STEP_BACK: + return ADDON_ACTION_CHAPTER_OR_BIG_STEP_BACK; + case ACTION_CYCLE_SUBTITLE: + return ADDON_ACTION_CYCLE_SUBTITLE; + case ACTION_MOUSE_LEFT_CLICK: + return ADDON_ACTION_MOUSE_LEFT_CLICK; + case ACTION_MOUSE_RIGHT_CLICK: + return ADDON_ACTION_MOUSE_RIGHT_CLICK; + case ACTION_MOUSE_MIDDLE_CLICK: + return ADDON_ACTION_MOUSE_MIDDLE_CLICK; + case ACTION_MOUSE_DOUBLE_CLICK: + return ADDON_ACTION_MOUSE_DOUBLE_CLICK; + case ACTION_MOUSE_WHEEL_UP: + return ADDON_ACTION_MOUSE_WHEEL_UP; + case ACTION_MOUSE_WHEEL_DOWN: + return ADDON_ACTION_MOUSE_WHEEL_DOWN; + case ACTION_MOUSE_DRAG: + return ADDON_ACTION_MOUSE_DRAG; + case ACTION_MOUSE_MOVE: + return ADDON_ACTION_MOUSE_MOVE; + case ACTION_MOUSE_LONG_CLICK: + return ADDON_ACTION_MOUSE_LONG_CLICK; + case ACTION_MOUSE_DRAG_END: + return ADDON_ACTION_MOUSE_DRAG_END; + case ACTION_BACKSPACE: + return ADDON_ACTION_BACKSPACE; + case ACTION_SCROLL_UP: + return ADDON_ACTION_SCROLL_UP; + case ACTION_SCROLL_DOWN: + return ADDON_ACTION_SCROLL_DOWN; + case ACTION_ANALOG_FORWARD: + return ADDON_ACTION_ANALOG_FORWARD; + case ACTION_ANALOG_REWIND: + return ADDON_ACTION_ANALOG_REWIND; + case ACTION_MOVE_ITEM_UP: + return ADDON_ACTION_MOVE_ITEM_UP; + case ACTION_MOVE_ITEM_DOWN: + return ADDON_ACTION_MOVE_ITEM_DOWN; + case ACTION_CONTEXT_MENU: + return ADDON_ACTION_CONTEXT_MENU; + case ACTION_SHIFT: + return ADDON_ACTION_SHIFT; + case ACTION_SYMBOLS: + return ADDON_ACTION_SYMBOLS; + case ACTION_CURSOR_LEFT: + return ADDON_ACTION_CURSOR_LEFT; + case ACTION_CURSOR_RIGHT: + return ADDON_ACTION_CURSOR_RIGHT; + case ACTION_BUILT_IN_FUNCTION: + return ADDON_ACTION_BUILT_IN_FUNCTION; + case ACTION_SHOW_OSD_TIME: + return ADDON_ACTION_SHOW_OSD_TIME; + case ACTION_ANALOG_SEEK_FORWARD: + return ADDON_ACTION_ANALOG_SEEK_FORWARD; + case ACTION_ANALOG_SEEK_BACK: + return ADDON_ACTION_ANALOG_SEEK_BACK; + case ACTION_VIS_PRESET_SHOW: + return ADDON_ACTION_VIS_PRESET_SHOW; + case ACTION_VIS_PRESET_NEXT: + return ADDON_ACTION_VIS_PRESET_NEXT; + case ACTION_VIS_PRESET_PREV: + return ADDON_ACTION_VIS_PRESET_PREV; + case ACTION_VIS_PRESET_LOCK: + return ADDON_ACTION_VIS_PRESET_LOCK; + case ACTION_VIS_PRESET_RANDOM: + return ADDON_ACTION_VIS_PRESET_RANDOM; + case ACTION_VIS_RATE_PRESET_PLUS: + return ADDON_ACTION_VIS_RATE_PRESET_PLUS; + case ACTION_VIS_RATE_PRESET_MINUS: + return ADDON_ACTION_VIS_RATE_PRESET_MINUS; + case ACTION_SHOW_VIDEOMENU: + return ADDON_ACTION_SHOW_VIDEOMENU; + case ACTION_ENTER: + return ADDON_ACTION_ENTER; + case ACTION_INCREASE_RATING: + return ADDON_ACTION_INCREASE_RATING; + case ACTION_DECREASE_RATING: + return ADDON_ACTION_DECREASE_RATING; + case ACTION_NEXT_SCENE: + return ADDON_ACTION_NEXT_SCENE; + case ACTION_PREV_SCENE: + return ADDON_ACTION_PREV_SCENE; + case ACTION_NEXT_LETTER: + return ADDON_ACTION_NEXT_LETTER; + case ACTION_PREV_LETTER: + return ADDON_ACTION_PREV_LETTER; + case ACTION_JUMP_SMS2: + return ADDON_ACTION_JUMP_SMS2; + case ACTION_JUMP_SMS3: + return ADDON_ACTION_JUMP_SMS3; + case ACTION_JUMP_SMS4: + return ADDON_ACTION_JUMP_SMS4; + case ACTION_JUMP_SMS5: + return ADDON_ACTION_JUMP_SMS5; + case ACTION_JUMP_SMS6: + return ADDON_ACTION_JUMP_SMS6; + case ACTION_JUMP_SMS7: + return ADDON_ACTION_JUMP_SMS7; + case ACTION_JUMP_SMS8: + return ADDON_ACTION_JUMP_SMS8; + case ACTION_JUMP_SMS9: + return ADDON_ACTION_JUMP_SMS9; + case ACTION_FILTER_CLEAR: + return ADDON_ACTION_FILTER_CLEAR; + case ACTION_FILTER_SMS2: + return ADDON_ACTION_FILTER_SMS2; + case ACTION_FILTER_SMS3: + return ADDON_ACTION_FILTER_SMS3; + case ACTION_FILTER_SMS4: + return ADDON_ACTION_FILTER_SMS4; + case ACTION_FILTER_SMS5: + return ADDON_ACTION_FILTER_SMS5; + case ACTION_FILTER_SMS6: + return ADDON_ACTION_FILTER_SMS6; + case ACTION_FILTER_SMS7: + return ADDON_ACTION_FILTER_SMS7; + case ACTION_FILTER_SMS8: + return ADDON_ACTION_FILTER_SMS8; + case ACTION_FILTER_SMS9: + return ADDON_ACTION_FILTER_SMS9; + case ACTION_FIRST_PAGE: + return ADDON_ACTION_FIRST_PAGE; + case ACTION_LAST_PAGE: + return ADDON_ACTION_LAST_PAGE; + case ACTION_AUDIO_DELAY: + return ADDON_ACTION_AUDIO_DELAY; + case ACTION_SUBTITLE_DELAY: + return ADDON_ACTION_SUBTITLE_DELAY; + case ACTION_MENU: + return ADDON_ACTION_MENU; + case ACTION_SET_RATING: + return ADDON_ACTION_SET_RATING; + case ACTION_RECORD: + return ADDON_ACTION_RECORD; + case ACTION_PASTE: + return ADDON_ACTION_PASTE; + case ACTION_NEXT_CONTROL: + return ADDON_ACTION_NEXT_CONTROL; + case ACTION_PREV_CONTROL: + return ADDON_ACTION_PREV_CONTROL; + case ACTION_CHANNEL_SWITCH: + return ADDON_ACTION_CHANNEL_SWITCH; + case ACTION_CHANNEL_UP: + return ADDON_ACTION_CHANNEL_UP; + case ACTION_CHANNEL_DOWN: + return ADDON_ACTION_CHANNEL_DOWN; + case ACTION_NEXT_CHANNELGROUP: + return ADDON_ACTION_NEXT_CHANNELGROUP; + case ACTION_PREVIOUS_CHANNELGROUP: + return ADDON_ACTION_PREVIOUS_CHANNELGROUP; + case ACTION_PVR_PLAY: + return ADDON_ACTION_PVR_PLAY; + case ACTION_PVR_PLAY_TV: + return ADDON_ACTION_PVR_PLAY_TV; + case ACTION_PVR_PLAY_RADIO: + return ADDON_ACTION_PVR_PLAY_RADIO; + case ACTION_PVR_SHOW_TIMER_RULE: + return ADDON_ACTION_PVR_SHOW_TIMER_RULE; + case ACTION_CHANNEL_NUMBER_SEP: + return ADDON_ACTION_CHANNEL_NUMBER_SEP; + case ACTION_PVR_ANNOUNCE_REMINDERS: + return ADDON_ACTION_PVR_ANNOUNCE_REMINDERS; + case ACTION_TOGGLE_FULLSCREEN: + return ADDON_ACTION_TOGGLE_FULLSCREEN; + case ACTION_TOGGLE_WATCHED: + return ADDON_ACTION_TOGGLE_WATCHED; + case ACTION_SCAN_ITEM: + return ADDON_ACTION_SCAN_ITEM; + case ACTION_TOGGLE_DIGITAL_ANALOG: + return ADDON_ACTION_TOGGLE_DIGITAL_ANALOG; + case ACTION_RELOAD_KEYMAPS: + return ADDON_ACTION_RELOAD_KEYMAPS; + case ACTION_GUIPROFILE_BEGIN: + return ADDON_ACTION_GUIPROFILE_BEGIN; + case ACTION_TELETEXT_RED: + return ADDON_ACTION_TELETEXT_RED; + case ACTION_TELETEXT_GREEN: + return ADDON_ACTION_TELETEXT_GREEN; + case ACTION_TELETEXT_YELLOW: + return ADDON_ACTION_TELETEXT_YELLOW; + case ACTION_TELETEXT_BLUE: + return ADDON_ACTION_TELETEXT_BLUE; + case ACTION_INCREASE_PAR: + return ADDON_ACTION_INCREASE_PAR; + case ACTION_DECREASE_PAR: + return ADDON_ACTION_DECREASE_PAR; + case ACTION_VSHIFT_UP: + return ADDON_ACTION_VSHIFT_UP; + case ACTION_VSHIFT_DOWN: + return ADDON_ACTION_VSHIFT_DOWN; + case ACTION_PLAYER_PLAYPAUSE: + return ADDON_ACTION_PLAYER_PLAYPAUSE; + case ACTION_SUBTITLE_VSHIFT_UP: + return ADDON_ACTION_SUBTITLE_VSHIFT_UP; + case ACTION_SUBTITLE_VSHIFT_DOWN: + return ADDON_ACTION_SUBTITLE_VSHIFT_DOWN; + case ACTION_SUBTITLE_ALIGN: + return ADDON_ACTION_SUBTITLE_ALIGN; + case ACTION_FILTER: + return ADDON_ACTION_FILTER; + case ACTION_SWITCH_PLAYER: + return ADDON_ACTION_SWITCH_PLAYER; + case ACTION_STEREOMODE_NEXT: + return ADDON_ACTION_STEREOMODE_NEXT; + case ACTION_STEREOMODE_PREVIOUS: + return ADDON_ACTION_STEREOMODE_PREVIOUS; + case ACTION_STEREOMODE_TOGGLE: + return ADDON_ACTION_STEREOMODE_TOGGLE; + case ACTION_STEREOMODE_SELECT: + return ADDON_ACTION_STEREOMODE_SELECT; + case ACTION_STEREOMODE_TOMONO: + return ADDON_ACTION_STEREOMODE_TOMONO; + case ACTION_STEREOMODE_SET: + return ADDON_ACTION_STEREOMODE_SET; + case ACTION_SETTINGS_RESET: + return ADDON_ACTION_SETTINGS_RESET; + case ACTION_SETTINGS_LEVEL_CHANGE: + return ADDON_ACTION_SETTINGS_LEVEL_CHANGE; + case ACTION_TRIGGER_OSD: + return ADDON_ACTION_TRIGGER_OSD; + case ACTION_INPUT_TEXT: + return ADDON_ACTION_INPUT_TEXT; + case ACTION_VOLUME_SET: + return ADDON_ACTION_VOLUME_SET; + case ACTION_TOGGLE_COMMSKIP: + return ADDON_ACTION_TOGGLE_COMMSKIP; + case ACTION_BROWSE_SUBTITLE: + return ADDON_ACTION_BROWSE_SUBTITLE; + case ACTION_PLAYER_RESET: + return ADDON_ACTION_PLAYER_RESET; + case ACTION_TOGGLE_FONT: + return ADDON_ACTION_TOGGLE_FONT; + case ACTION_VIDEO_NEXT_STREAM: + return ADDON_ACTION_VIDEO_NEXT_STREAM; + case ACTION_QUEUE_ITEM_NEXT: + return ADDON_ACTION_QUEUE_ITEM_NEXT; + case ACTION_HDR_TOGGLE: + return ADDON_ACTION_HDR_TOGGLE; + case ACTION_VOICE_RECOGNIZE: + return ADDON_ACTION_VOICE_RECOGNIZE; + case ACTION_TOUCH_TAP: + return ADDON_ACTION_TOUCH_TAP; + case ACTION_TOUCH_TAP_TEN: + return ADDON_ACTION_TOUCH_TAP_TEN; + case ACTION_TOUCH_LONGPRESS: + return ADDON_ACTION_TOUCH_LONGPRESS; + case ACTION_TOUCH_LONGPRESS_TEN: + return ADDON_ACTION_TOUCH_LONGPRESS_TEN; + case ACTION_GESTURE_NOTIFY: + return ADDON_ACTION_GESTURE_NOTIFY; + case ACTION_GESTURE_BEGIN: + return ADDON_ACTION_GESTURE_BEGIN; + case ACTION_GESTURE_ZOOM: + return ADDON_ACTION_GESTURE_ZOOM; + case ACTION_GESTURE_ROTATE: + return ADDON_ACTION_GESTURE_ROTATE; + case ACTION_GESTURE_PAN: + return ADDON_ACTION_GESTURE_PAN; + case ACTION_GESTURE_ABORT: + return ADDON_ACTION_GESTURE_ABORT; + case ACTION_GESTURE_SWIPE_LEFT: + return ADDON_ACTION_GESTURE_SWIPE_LEFT; + case ACTION_GESTURE_SWIPE_LEFT_TEN: + return ADDON_ACTION_GESTURE_SWIPE_LEFT_TEN; + case ACTION_GESTURE_SWIPE_RIGHT: + return ADDON_ACTION_GESTURE_SWIPE_RIGHT; + case ACTION_GESTURE_SWIPE_RIGHT_TEN: + return ADDON_ACTION_GESTURE_SWIPE_RIGHT_TEN; + case ACTION_GESTURE_SWIPE_UP: + return ADDON_ACTION_GESTURE_SWIPE_UP; + case ACTION_GESTURE_SWIPE_UP_TEN: + return ADDON_ACTION_GESTURE_SWIPE_UP_TEN; + case ACTION_GESTURE_SWIPE_DOWN: + return ADDON_ACTION_GESTURE_SWIPE_DOWN; + case ACTION_GESTURE_SWIPE_DOWN_TEN: + return ADDON_ACTION_GESTURE_SWIPE_DOWN_TEN; + case ACTION_GESTURE_END: + return ADDON_ACTION_GESTURE_END; + case ACTION_ANALOG_MOVE_X_LEFT: + return ADDON_ACTION_ANALOG_MOVE_X_LEFT; + case ACTION_ANALOG_MOVE_X_RIGHT: + return ADDON_ACTION_ANALOG_MOVE_X_RIGHT; + case ACTION_ANALOG_MOVE_Y_UP: + return ADDON_ACTION_ANALOG_MOVE_Y_UP; + case ACTION_ANALOG_MOVE_Y_DOWN: + return ADDON_ACTION_ANALOG_MOVE_Y_DOWN; + case ACTION_ERROR: + return ADDON_ACTION_ERROR; + case ACTION_NOOP: + default: + return ADDON_ACTION_NOOP; + } +} + +int CAddonGUITranslator::TranslateActionIdToKodi(ADDON_ACTION addonId) +{ + switch (addonId) + { + case ADDON_ACTION_NONE: + return ACTION_NONE; + case ADDON_ACTION_MOVE_LEFT: + return ACTION_MOVE_LEFT; + case ADDON_ACTION_MOVE_RIGHT: + return ACTION_MOVE_RIGHT; + case ADDON_ACTION_MOVE_UP: + return ACTION_MOVE_UP; + case ADDON_ACTION_MOVE_DOWN: + return ACTION_MOVE_DOWN; + case ADDON_ACTION_PAGE_UP: + return ACTION_PAGE_UP; + case ADDON_ACTION_PAGE_DOWN: + return ACTION_PAGE_DOWN; + case ADDON_ACTION_SELECT_ITEM: + return ACTION_SELECT_ITEM; + case ADDON_ACTION_HIGHLIGHT_ITEM: + return ACTION_HIGHLIGHT_ITEM; + case ADDON_ACTION_PARENT_DIR: + return ACTION_PARENT_DIR; + case ADDON_ACTION_PREVIOUS_MENU: + return ACTION_PREVIOUS_MENU; + case ADDON_ACTION_SHOW_INFO: + return ACTION_SHOW_INFO; + case ADDON_ACTION_PAUSE: + return ACTION_PAUSE; + case ADDON_ACTION_STOP: + return ACTION_STOP; + case ADDON_ACTION_NEXT_ITEM: + return ACTION_NEXT_ITEM; + case ADDON_ACTION_PREV_ITEM: + return ACTION_PREV_ITEM; + case ADDON_ACTION_FORWARD: + return ACTION_FORWARD; + case ADDON_ACTION_REWIND: + return ACTION_REWIND; + case ADDON_ACTION_SHOW_GUI: + return ACTION_SHOW_GUI; + case ADDON_ACTION_ASPECT_RATIO: + return ACTION_ASPECT_RATIO; + case ADDON_ACTION_STEP_FORWARD: + return ACTION_STEP_FORWARD; + case ADDON_ACTION_STEP_BACK: + return ACTION_STEP_BACK; + case ADDON_ACTION_BIG_STEP_FORWARD: + return ACTION_BIG_STEP_FORWARD; + case ADDON_ACTION_BIG_STEP_BACK: + return ACTION_BIG_STEP_BACK; + case ADDON_ACTION_SHOW_OSD: + return ACTION_SHOW_OSD; + case ADDON_ACTION_SHOW_SUBTITLES: + return ACTION_SHOW_SUBTITLES; + case ADDON_ACTION_NEXT_SUBTITLE: + return ACTION_NEXT_SUBTITLE; + case ADDON_ACTION_PLAYER_DEBUG: + return ACTION_PLAYER_DEBUG; + case ADDON_ACTION_NEXT_PICTURE: + return ACTION_NEXT_PICTURE; + case ADDON_ACTION_PREV_PICTURE: + return ACTION_PREV_PICTURE; + case ADDON_ACTION_ZOOM_OUT: + return ACTION_ZOOM_OUT; + case ADDON_ACTION_ZOOM_IN: + return ACTION_ZOOM_IN; + case ADDON_ACTION_TOGGLE_SOURCE_DEST: + return ACTION_TOGGLE_SOURCE_DEST; + case ADDON_ACTION_SHOW_PLAYLIST: + return ACTION_SHOW_PLAYLIST; + case ADDON_ACTION_QUEUE_ITEM: + return ACTION_QUEUE_ITEM; + case ADDON_ACTION_REMOVE_ITEM: + return ACTION_REMOVE_ITEM; + case ADDON_ACTION_SHOW_FULLSCREEN: + return ACTION_SHOW_FULLSCREEN; + case ADDON_ACTION_ZOOM_LEVEL_NORMAL: + return ACTION_ZOOM_LEVEL_NORMAL; + case ADDON_ACTION_ZOOM_LEVEL_1: + return ACTION_ZOOM_LEVEL_1; + case ADDON_ACTION_ZOOM_LEVEL_2: + return ACTION_ZOOM_LEVEL_2; + case ADDON_ACTION_ZOOM_LEVEL_3: + return ACTION_ZOOM_LEVEL_3; + case ADDON_ACTION_ZOOM_LEVEL_4: + return ACTION_ZOOM_LEVEL_4; + case ADDON_ACTION_ZOOM_LEVEL_5: + return ACTION_ZOOM_LEVEL_5; + case ADDON_ACTION_ZOOM_LEVEL_6: + return ACTION_ZOOM_LEVEL_6; + case ADDON_ACTION_ZOOM_LEVEL_7: + return ACTION_ZOOM_LEVEL_7; + case ADDON_ACTION_ZOOM_LEVEL_8: + return ACTION_ZOOM_LEVEL_8; + case ADDON_ACTION_ZOOM_LEVEL_9: + return ACTION_ZOOM_LEVEL_9; + case ADDON_ACTION_CALIBRATE_SWAP_ARROWS: + return ACTION_CALIBRATE_SWAP_ARROWS; + case ADDON_ACTION_CALIBRATE_RESET: + return ACTION_CALIBRATE_RESET; + case ADDON_ACTION_ANALOG_MOVE: + return ACTION_ANALOG_MOVE; + case ADDON_ACTION_ROTATE_PICTURE_CW: + return ACTION_ROTATE_PICTURE_CW; + case ADDON_ACTION_ROTATE_PICTURE_CCW: + return ACTION_ROTATE_PICTURE_CCW; + case ADDON_ACTION_SUBTITLE_DELAY_MIN: + return ACTION_SUBTITLE_DELAY_MIN; + case ADDON_ACTION_SUBTITLE_DELAY_PLUS: + return ACTION_SUBTITLE_DELAY_PLUS; + case ADDON_ACTION_AUDIO_DELAY_MIN: + return ACTION_AUDIO_DELAY_MIN; + case ADDON_ACTION_AUDIO_DELAY_PLUS: + return ACTION_AUDIO_DELAY_PLUS; + case ADDON_ACTION_AUDIO_NEXT_LANGUAGE: + return ACTION_AUDIO_NEXT_LANGUAGE; + case ADDON_ACTION_CHANGE_RESOLUTION: + return ACTION_CHANGE_RESOLUTION; + case ADDON_ACTION_REMOTE_0: + return REMOTE_0; + case ADDON_ACTION_REMOTE_1: + return REMOTE_1; + case ADDON_ACTION_REMOTE_2: + return REMOTE_2; + case ADDON_ACTION_REMOTE_3: + return REMOTE_3; + case ADDON_ACTION_REMOTE_4: + return REMOTE_4; + case ADDON_ACTION_REMOTE_5: + return REMOTE_5; + case ADDON_ACTION_REMOTE_6: + return REMOTE_6; + case ADDON_ACTION_REMOTE_7: + return REMOTE_7; + case ADDON_ACTION_REMOTE_8: + return REMOTE_8; + case ADDON_ACTION_REMOTE_9: + return REMOTE_9; + case ADDON_ACTION_PLAYER_PROCESS_INFO: + return ACTION_PLAYER_PROCESS_INFO; + case ADDON_ACTION_PLAYER_PROGRAM_SELECT: + return ACTION_PLAYER_PROGRAM_SELECT; + case ADDON_ACTION_PLAYER_RESOLUTION_SELECT: + return ACTION_PLAYER_RESOLUTION_SELECT; + case ADDON_ACTION_SMALL_STEP_BACK: + return ACTION_SMALL_STEP_BACK; + case ADDON_ACTION_PLAYER_FORWARD: + return ACTION_PLAYER_FORWARD; + case ADDON_ACTION_PLAYER_REWIND: + return ACTION_PLAYER_REWIND; + case ADDON_ACTION_PLAYER_PLAY: + return ACTION_PLAYER_PLAY; + case ADDON_ACTION_DELETE_ITEM: + return ACTION_DELETE_ITEM; + case ADDON_ACTION_COPY_ITEM: + return ACTION_COPY_ITEM; + case ADDON_ACTION_MOVE_ITEM: + return ACTION_MOVE_ITEM; + case ADDON_ACTION_TAKE_SCREENSHOT: + return ACTION_TAKE_SCREENSHOT; + case ADDON_ACTION_RENAME_ITEM: + return ACTION_RENAME_ITEM; + case ADDON_ACTION_VOLUME_UP: + return ACTION_VOLUME_UP; + case ADDON_ACTION_VOLUME_DOWN: + return ACTION_VOLUME_DOWN; + case ADDON_ACTION_VOLAMP: + return ACTION_VOLAMP; + case ADDON_ACTION_MUTE: + return ACTION_MUTE; + case ADDON_ACTION_NAV_BACK: + return ACTION_NAV_BACK; + case ADDON_ACTION_VOLAMP_UP: + return ACTION_VOLAMP_UP; + case ADDON_ACTION_VOLAMP_DOWN: + return ACTION_VOLAMP_DOWN; + case ADDON_ACTION_CREATE_EPISODE_BOOKMARK: + return ACTION_CREATE_EPISODE_BOOKMARK; + case ADDON_ACTION_CREATE_BOOKMARK: + return ACTION_CREATE_BOOKMARK; + case ADDON_ACTION_CHAPTER_OR_BIG_STEP_FORWARD: + return ACTION_CHAPTER_OR_BIG_STEP_FORWARD; + case ADDON_ACTION_CHAPTER_OR_BIG_STEP_BACK: + return ACTION_CHAPTER_OR_BIG_STEP_BACK; + case ADDON_ACTION_CYCLE_SUBTITLE: + return ACTION_CYCLE_SUBTITLE; + case ADDON_ACTION_MOUSE_LEFT_CLICK: + return ACTION_MOUSE_LEFT_CLICK; + case ADDON_ACTION_MOUSE_RIGHT_CLICK: + return ACTION_MOUSE_RIGHT_CLICK; + case ADDON_ACTION_MOUSE_MIDDLE_CLICK: + return ACTION_MOUSE_MIDDLE_CLICK; + case ADDON_ACTION_MOUSE_DOUBLE_CLICK: + return ACTION_MOUSE_DOUBLE_CLICK; + case ADDON_ACTION_MOUSE_WHEEL_UP: + return ACTION_MOUSE_WHEEL_UP; + case ADDON_ACTION_MOUSE_WHEEL_DOWN: + return ACTION_MOUSE_WHEEL_DOWN; + case ADDON_ACTION_MOUSE_DRAG: + return ACTION_MOUSE_DRAG; + case ADDON_ACTION_MOUSE_MOVE: + return ACTION_MOUSE_MOVE; + case ADDON_ACTION_MOUSE_LONG_CLICK: + return ACTION_MOUSE_LONG_CLICK; + case ADDON_ACTION_MOUSE_DRAG_END: + return ACTION_MOUSE_DRAG_END; + case ADDON_ACTION_BACKSPACE: + return ACTION_BACKSPACE; + case ADDON_ACTION_SCROLL_UP: + return ACTION_SCROLL_UP; + case ADDON_ACTION_SCROLL_DOWN: + return ACTION_SCROLL_DOWN; + case ADDON_ACTION_ANALOG_FORWARD: + return ACTION_ANALOG_FORWARD; + case ADDON_ACTION_ANALOG_REWIND: + return ACTION_ANALOG_REWIND; + case ADDON_ACTION_MOVE_ITEM_UP: + return ACTION_MOVE_ITEM_UP; + case ADDON_ACTION_MOVE_ITEM_DOWN: + return ACTION_MOVE_ITEM_DOWN; + case ADDON_ACTION_CONTEXT_MENU: + return ACTION_CONTEXT_MENU; + case ADDON_ACTION_SHIFT: + return ACTION_SHIFT; + case ADDON_ACTION_SYMBOLS: + return ACTION_SYMBOLS; + case ADDON_ACTION_CURSOR_LEFT: + return ACTION_CURSOR_LEFT; + case ADDON_ACTION_CURSOR_RIGHT: + return ACTION_CURSOR_RIGHT; + case ADDON_ACTION_BUILT_IN_FUNCTION: + return ACTION_BUILT_IN_FUNCTION; + case ADDON_ACTION_SHOW_OSD_TIME: + return ACTION_SHOW_OSD_TIME; + case ADDON_ACTION_ANALOG_SEEK_FORWARD: + return ACTION_ANALOG_SEEK_FORWARD; + case ADDON_ACTION_ANALOG_SEEK_BACK: + return ACTION_ANALOG_SEEK_BACK; + case ADDON_ACTION_VIS_PRESET_SHOW: + return ACTION_VIS_PRESET_SHOW; + case ADDON_ACTION_VIS_PRESET_NEXT: + return ACTION_VIS_PRESET_NEXT; + case ADDON_ACTION_VIS_PRESET_PREV: + return ACTION_VIS_PRESET_PREV; + case ADDON_ACTION_VIS_PRESET_LOCK: + return ACTION_VIS_PRESET_LOCK; + case ADDON_ACTION_VIS_PRESET_RANDOM: + return ACTION_VIS_PRESET_RANDOM; + case ADDON_ACTION_VIS_RATE_PRESET_PLUS: + return ACTION_VIS_RATE_PRESET_PLUS; + case ADDON_ACTION_VIS_RATE_PRESET_MINUS: + return ACTION_VIS_RATE_PRESET_MINUS; + case ADDON_ACTION_SHOW_VIDEOMENU: + return ACTION_SHOW_VIDEOMENU; + case ADDON_ACTION_ENTER: + return ACTION_ENTER; + case ADDON_ACTION_INCREASE_RATING: + return ACTION_INCREASE_RATING; + case ADDON_ACTION_DECREASE_RATING: + return ACTION_DECREASE_RATING; + case ADDON_ACTION_NEXT_SCENE: + return ACTION_NEXT_SCENE; + case ADDON_ACTION_PREV_SCENE: + return ACTION_PREV_SCENE; + case ADDON_ACTION_NEXT_LETTER: + return ACTION_NEXT_LETTER; + case ADDON_ACTION_PREV_LETTER: + return ACTION_PREV_LETTER; + case ADDON_ACTION_JUMP_SMS2: + return ACTION_JUMP_SMS2; + case ADDON_ACTION_JUMP_SMS3: + return ACTION_JUMP_SMS3; + case ADDON_ACTION_JUMP_SMS4: + return ACTION_JUMP_SMS4; + case ADDON_ACTION_JUMP_SMS5: + return ACTION_JUMP_SMS5; + case ADDON_ACTION_JUMP_SMS6: + return ACTION_JUMP_SMS6; + case ADDON_ACTION_JUMP_SMS7: + return ACTION_JUMP_SMS7; + case ADDON_ACTION_JUMP_SMS8: + return ACTION_JUMP_SMS8; + case ADDON_ACTION_JUMP_SMS9: + return ACTION_JUMP_SMS9; + case ADDON_ACTION_FILTER_CLEAR: + return ACTION_FILTER_CLEAR; + case ADDON_ACTION_FILTER_SMS2: + return ACTION_FILTER_SMS2; + case ADDON_ACTION_FILTER_SMS3: + return ACTION_FILTER_SMS3; + case ADDON_ACTION_FILTER_SMS4: + return ACTION_FILTER_SMS4; + case ADDON_ACTION_FILTER_SMS5: + return ACTION_FILTER_SMS5; + case ADDON_ACTION_FILTER_SMS6: + return ACTION_FILTER_SMS6; + case ADDON_ACTION_FILTER_SMS7: + return ACTION_FILTER_SMS7; + case ADDON_ACTION_FILTER_SMS8: + return ACTION_FILTER_SMS8; + case ADDON_ACTION_FILTER_SMS9: + return ACTION_FILTER_SMS9; + case ADDON_ACTION_FIRST_PAGE: + return ACTION_FIRST_PAGE; + case ADDON_ACTION_LAST_PAGE: + return ACTION_LAST_PAGE; + case ADDON_ACTION_AUDIO_DELAY: + return ACTION_AUDIO_DELAY; + case ADDON_ACTION_SUBTITLE_DELAY: + return ACTION_SUBTITLE_DELAY; + case ADDON_ACTION_MENU: + return ACTION_MENU; + case ADDON_ACTION_SET_RATING: + return ACTION_SET_RATING; + case ADDON_ACTION_RECORD: + return ACTION_RECORD; + case ADDON_ACTION_PASTE: + return ACTION_PASTE; + case ADDON_ACTION_NEXT_CONTROL: + return ACTION_NEXT_CONTROL; + case ADDON_ACTION_PREV_CONTROL: + return ACTION_PREV_CONTROL; + case ADDON_ACTION_CHANNEL_SWITCH: + return ACTION_CHANNEL_SWITCH; + case ADDON_ACTION_CHANNEL_UP: + return ACTION_CHANNEL_UP; + case ADDON_ACTION_CHANNEL_DOWN: + return ACTION_CHANNEL_DOWN; + case ADDON_ACTION_NEXT_CHANNELGROUP: + return ACTION_NEXT_CHANNELGROUP; + case ADDON_ACTION_PREVIOUS_CHANNELGROUP: + return ACTION_PREVIOUS_CHANNELGROUP; + case ADDON_ACTION_PVR_PLAY: + return ACTION_PVR_PLAY; + case ADDON_ACTION_PVR_PLAY_TV: + return ACTION_PVR_PLAY_TV; + case ADDON_ACTION_PVR_PLAY_RADIO: + return ACTION_PVR_PLAY_RADIO; + case ADDON_ACTION_PVR_SHOW_TIMER_RULE: + return ACTION_PVR_SHOW_TIMER_RULE; + case ADDON_ACTION_CHANNEL_NUMBER_SEP: + return ACTION_CHANNEL_NUMBER_SEP; + case ADDON_ACTION_PVR_ANNOUNCE_REMINDERS: + return ACTION_PVR_ANNOUNCE_REMINDERS; + case ADDON_ACTION_TOGGLE_FULLSCREEN: + return ACTION_TOGGLE_FULLSCREEN; + case ADDON_ACTION_TOGGLE_WATCHED: + return ACTION_TOGGLE_WATCHED; + case ADDON_ACTION_SCAN_ITEM: + return ACTION_SCAN_ITEM; + case ADDON_ACTION_TOGGLE_DIGITAL_ANALOG: + return ACTION_TOGGLE_DIGITAL_ANALOG; + case ADDON_ACTION_RELOAD_KEYMAPS: + return ACTION_RELOAD_KEYMAPS; + case ADDON_ACTION_GUIPROFILE_BEGIN: + return ACTION_GUIPROFILE_BEGIN; + case ADDON_ACTION_TELETEXT_RED: + return ACTION_TELETEXT_RED; + case ADDON_ACTION_TELETEXT_GREEN: + return ACTION_TELETEXT_GREEN; + case ADDON_ACTION_TELETEXT_YELLOW: + return ACTION_TELETEXT_YELLOW; + case ADDON_ACTION_TELETEXT_BLUE: + return ACTION_TELETEXT_BLUE; + case ADDON_ACTION_INCREASE_PAR: + return ACTION_INCREASE_PAR; + case ADDON_ACTION_DECREASE_PAR: + return ACTION_DECREASE_PAR; + case ADDON_ACTION_VSHIFT_UP: + return ACTION_VSHIFT_UP; + case ADDON_ACTION_VSHIFT_DOWN: + return ACTION_VSHIFT_DOWN; + case ADDON_ACTION_PLAYER_PLAYPAUSE: + return ACTION_PLAYER_PLAYPAUSE; + case ADDON_ACTION_SUBTITLE_VSHIFT_UP: + return ACTION_SUBTITLE_VSHIFT_UP; + case ADDON_ACTION_SUBTITLE_VSHIFT_DOWN: + return ACTION_SUBTITLE_VSHIFT_DOWN; + case ADDON_ACTION_SUBTITLE_ALIGN: + return ACTION_SUBTITLE_ALIGN; + case ADDON_ACTION_FILTER: + return ACTION_FILTER; + case ADDON_ACTION_SWITCH_PLAYER: + return ACTION_SWITCH_PLAYER; + case ADDON_ACTION_STEREOMODE_NEXT: + return ACTION_STEREOMODE_NEXT; + case ADDON_ACTION_STEREOMODE_PREVIOUS: + return ACTION_STEREOMODE_PREVIOUS; + case ADDON_ACTION_STEREOMODE_TOGGLE: + return ACTION_STEREOMODE_TOGGLE; + case ADDON_ACTION_STEREOMODE_SELECT: + return ACTION_STEREOMODE_SELECT; + case ADDON_ACTION_STEREOMODE_TOMONO: + return ACTION_STEREOMODE_TOMONO; + case ADDON_ACTION_STEREOMODE_SET: + return ACTION_STEREOMODE_SET; + case ADDON_ACTION_SETTINGS_RESET: + return ACTION_SETTINGS_RESET; + case ADDON_ACTION_SETTINGS_LEVEL_CHANGE: + return ACTION_SETTINGS_LEVEL_CHANGE; + case ADDON_ACTION_TRIGGER_OSD: + return ACTION_TRIGGER_OSD; + case ADDON_ACTION_INPUT_TEXT: + return ACTION_INPUT_TEXT; + case ADDON_ACTION_VOLUME_SET: + return ACTION_VOLUME_SET; + case ADDON_ACTION_TOGGLE_COMMSKIP: + return ACTION_TOGGLE_COMMSKIP; + case ADDON_ACTION_BROWSE_SUBTITLE: + return ACTION_BROWSE_SUBTITLE; + case ADDON_ACTION_PLAYER_RESET: + return ACTION_PLAYER_RESET; + case ADDON_ACTION_TOGGLE_FONT: + return ACTION_TOGGLE_FONT; + case ADDON_ACTION_VIDEO_NEXT_STREAM: + return ACTION_VIDEO_NEXT_STREAM; + case ADDON_ACTION_QUEUE_ITEM_NEXT: + return ACTION_QUEUE_ITEM_NEXT; + case ADDON_ACTION_HDR_TOGGLE: + return ACTION_HDR_TOGGLE; + case ADDON_ACTION_VOICE_RECOGNIZE: + return ACTION_VOICE_RECOGNIZE; + case ADDON_ACTION_TOUCH_TAP: + return ACTION_TOUCH_TAP; + case ADDON_ACTION_TOUCH_TAP_TEN: + return ACTION_TOUCH_TAP_TEN; + case ADDON_ACTION_TOUCH_LONGPRESS: + return ACTION_TOUCH_LONGPRESS; + case ADDON_ACTION_TOUCH_LONGPRESS_TEN: + return ACTION_TOUCH_LONGPRESS_TEN; + case ADDON_ACTION_GESTURE_NOTIFY: + return ACTION_GESTURE_NOTIFY; + case ADDON_ACTION_GESTURE_BEGIN: + return ACTION_GESTURE_BEGIN; + case ADDON_ACTION_GESTURE_ZOOM: + return ACTION_GESTURE_ZOOM; + case ADDON_ACTION_GESTURE_ROTATE: + return ACTION_GESTURE_ROTATE; + case ADDON_ACTION_GESTURE_PAN: + return ACTION_GESTURE_PAN; + case ADDON_ACTION_GESTURE_ABORT: + return ACTION_GESTURE_ABORT; + case ADDON_ACTION_GESTURE_SWIPE_LEFT: + return ACTION_GESTURE_SWIPE_LEFT; + case ADDON_ACTION_GESTURE_SWIPE_LEFT_TEN: + return ACTION_GESTURE_SWIPE_LEFT_TEN; + case ADDON_ACTION_GESTURE_SWIPE_RIGHT: + return ACTION_GESTURE_SWIPE_RIGHT; + case ADDON_ACTION_GESTURE_SWIPE_RIGHT_TEN: + return ACTION_GESTURE_SWIPE_RIGHT_TEN; + case ADDON_ACTION_GESTURE_SWIPE_UP: + return ACTION_GESTURE_SWIPE_UP; + case ADDON_ACTION_GESTURE_SWIPE_UP_TEN: + return ACTION_GESTURE_SWIPE_UP_TEN; + case ADDON_ACTION_GESTURE_SWIPE_DOWN: + return ACTION_GESTURE_SWIPE_DOWN; + case ADDON_ACTION_GESTURE_SWIPE_DOWN_TEN: + return ACTION_GESTURE_SWIPE_DOWN_TEN; + case ADDON_ACTION_GESTURE_END: + return ACTION_GESTURE_END; + case ADDON_ACTION_ANALOG_MOVE_X_LEFT: + return ACTION_ANALOG_MOVE_X_LEFT; + case ADDON_ACTION_ANALOG_MOVE_X_RIGHT: + return ACTION_ANALOG_MOVE_X_RIGHT; + case ADDON_ACTION_ANALOG_MOVE_Y_UP: + return ACTION_ANALOG_MOVE_Y_UP; + case ADDON_ACTION_ANALOG_MOVE_Y_DOWN: + return ACTION_ANALOG_MOVE_Y_DOWN; + case ADDON_ACTION_ERROR: + return ACTION_ERROR; + case ADDON_ACTION_NOOP: + default: + return ACTION_NOOP; + } +} diff --git a/xbmc/addons/interfaces/gui/GUITranslator.h b/xbmc/addons/interfaces/gui/GUITranslator.h new file mode 100644 index 0000000..8bd6b5c --- /dev/null +++ b/xbmc/addons/interfaces/gui/GUITranslator.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h" + +namespace ADDON +{ + +/*! + * \brief Translates data types from GUI API to the corresponding format in Kodi. + * + * This class is stateless. + */ +class CAddonGUITranslator +{ + CAddonGUITranslator() = delete; + +public: + /*! + * \brief Translate Kodi's action id's to addon + * \param kodiId Kodi's action identifier + * \return Addon action identifier + */ + static ADDON_ACTION TranslateActionIdToAddon(int kodiId); + + /*! + * \brief Translate addon's action id's to Kodi + * \param addonId Addon's action identifier + * \return Kodi action identifier + */ + static int TranslateActionIdToKodi(ADDON_ACTION addonId); +}; + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/General.cpp b/xbmc/addons/interfaces/gui/General.cpp new file mode 100644 index 0000000..a0a5583 --- /dev/null +++ b/xbmc/addons/interfaces/gui/General.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "General.h" + +#include "ListItem.h" +#include "ServiceBroker.h" +#include "Window.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/General.h" +#include "controls/Button.h" +#include "controls/Edit.h" +#include "controls/FadeLabel.h" +#include "controls/Image.h" +#include "controls/Label.h" +#include "controls/Progress.h" +#include "controls/RadioButton.h" +#include "controls/Rendering.h" +#include "controls/SettingsSlider.h" +#include "controls/Slider.h" +#include "controls/Spin.h" +#include "controls/TextBox.h" +#include "dialogs/ContextMenu.h" +#include "dialogs/ExtendedProgressBar.h" +#include "dialogs/FileBrowser.h" +#include "dialogs/Keyboard.h" +#include "dialogs/Numeric.h" +#include "dialogs/OK.h" +#include "dialogs/Progress.h" +#include "dialogs/Select.h" +#include "dialogs/TextViewer.h" +#include "dialogs/YesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/log.h" + +#include <mutex> + +namespace ADDON +{ +int Interface_GUIGeneral::m_iAddonGUILockRef = 0; + +void Interface_GUIGeneral::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui = new AddonToKodiFuncTable_kodi_gui(); + + Interface_GUIControlButton::Init(addonInterface); + Interface_GUIControlEdit::Init(addonInterface); + Interface_GUIControlFadeLabel::Init(addonInterface); + Interface_GUIControlImage::Init(addonInterface); + Interface_GUIControlLabel::Init(addonInterface); + Interface_GUIControlProgress::Init(addonInterface); + Interface_GUIControlRadioButton::Init(addonInterface); + Interface_GUIControlAddonRendering::Init(addonInterface); + Interface_GUIControlSettingsSlider::Init(addonInterface); + Interface_GUIControlSlider::Init(addonInterface); + Interface_GUIControlSpin::Init(addonInterface); + Interface_GUIControlTextBox::Init(addonInterface); + Interface_GUIDialogContextMenu::Init(addonInterface); + Interface_GUIDialogExtendedProgress::Init(addonInterface); + Interface_GUIDialogFileBrowser::Init(addonInterface); + Interface_GUIDialogKeyboard::Init(addonInterface); + Interface_GUIDialogNumeric::Init(addonInterface); + Interface_GUIDialogOK::Init(addonInterface); + Interface_GUIDialogProgress::Init(addonInterface); + Interface_GUIDialogSelect::Init(addonInterface); + Interface_GUIDialogTextViewer::Init(addonInterface); + Interface_GUIDialogYesNo::Init(addonInterface); + Interface_GUIListItem::Init(addonInterface); + Interface_GUIWindow::Init(addonInterface); + + addonInterface->toKodi->kodi_gui->general = new AddonToKodiFuncTable_kodi_gui_general(); + + addonInterface->toKodi->kodi_gui->general->lock = lock; + addonInterface->toKodi->kodi_gui->general->unlock = unlock; + addonInterface->toKodi->kodi_gui->general->get_screen_height = get_screen_height; + addonInterface->toKodi->kodi_gui->general->get_screen_width = get_screen_width; + addonInterface->toKodi->kodi_gui->general->get_video_resolution = get_video_resolution; + addonInterface->toKodi->kodi_gui->general->get_current_window_dialog_id = + get_current_window_dialog_id; + addonInterface->toKodi->kodi_gui->general->get_current_window_id = get_current_window_id; + addonInterface->toKodi->kodi_gui->general->get_hw_context = get_hw_context; + addonInterface->toKodi->kodi_gui->general->get_adjust_refresh_rate_status = + get_adjust_refresh_rate_status; +} + +void Interface_GUIGeneral::DeInit(AddonGlobalInterface* addonInterface) +{ + if (addonInterface->toKodi && /* <-- needed as long as the old addon way is used */ + addonInterface->toKodi->kodi_gui) + { + Interface_GUIControlButton::DeInit(addonInterface); + Interface_GUIControlEdit::DeInit(addonInterface); + Interface_GUIControlFadeLabel::DeInit(addonInterface); + Interface_GUIControlImage::DeInit(addonInterface); + Interface_GUIControlLabel::DeInit(addonInterface); + Interface_GUIControlProgress::DeInit(addonInterface); + Interface_GUIControlRadioButton::DeInit(addonInterface); + Interface_GUIControlAddonRendering::DeInit(addonInterface); + Interface_GUIControlSettingsSlider::DeInit(addonInterface); + Interface_GUIControlSlider::DeInit(addonInterface); + Interface_GUIControlSpin::DeInit(addonInterface); + Interface_GUIControlTextBox::DeInit(addonInterface); + Interface_GUIDialogContextMenu::DeInit(addonInterface); + Interface_GUIDialogExtendedProgress::DeInit(addonInterface); + Interface_GUIDialogFileBrowser::DeInit(addonInterface); + Interface_GUIDialogKeyboard::DeInit(addonInterface); + Interface_GUIDialogNumeric::DeInit(addonInterface); + Interface_GUIDialogOK::DeInit(addonInterface); + Interface_GUIDialogProgress::DeInit(addonInterface); + Interface_GUIDialogSelect::DeInit(addonInterface); + Interface_GUIDialogTextViewer::DeInit(addonInterface); + Interface_GUIDialogYesNo::DeInit(addonInterface); + Interface_GUIListItem::DeInit(addonInterface); + Interface_GUIWindow::DeInit(addonInterface); + + delete addonInterface->toKodi->kodi_gui->general; + delete addonInterface->toKodi->kodi_gui; + addonInterface->toKodi->kodi_gui = nullptr; + } +} + +//@{ +void Interface_GUIGeneral::lock() +{ + if (m_iAddonGUILockRef == 0) + CServiceBroker::GetWinSystem()->GetGfxContext().lock(); + ++m_iAddonGUILockRef; +} + +void Interface_GUIGeneral::unlock() +{ + if (m_iAddonGUILockRef > 0) + { + --m_iAddonGUILockRef; + if (m_iAddonGUILockRef == 0) + CServiceBroker::GetWinSystem()->GetGfxContext().unlock(); + } +} +//@} + +//@{ +int Interface_GUIGeneral::get_screen_height(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "kodi::gui::{} - invalid data", __func__); + return -1; + } + + return CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight(); +} + +int Interface_GUIGeneral::get_screen_width(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "kodi::gui::{} - invalid data", __func__); + return -1; + } + + return CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth(); +} + +int Interface_GUIGeneral::get_video_resolution(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "kodi::gui::{} - invalid data", __func__); + return -1; + } + + return (int)CServiceBroker::GetWinSystem()->GetGfxContext().GetVideoResolution(); +} +//@} + +//@{ +int Interface_GUIGeneral::get_current_window_dialog_id(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "kodi::gui::{} - invalid data", __func__); + return -1; + } + + std::unique_lock<CCriticalSection> gl(CServiceBroker::GetWinSystem()->GetGfxContext()); + return CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog(); +} + +int Interface_GUIGeneral::get_current_window_id(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "kodi::gui::{} - invalid data", __func__); + return -1; + } + + std::unique_lock<CCriticalSection> gl(CServiceBroker::GetWinSystem()->GetGfxContext()); + return CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(); +} + +ADDON_HARDWARE_CONTEXT Interface_GUIGeneral::get_hw_context(KODI_HANDLE kodiBase) +{ + return CServiceBroker::GetWinSystem()->GetHWContext(); +} + +AdjustRefreshRateStatus Interface_GUIGeneral::get_adjust_refresh_rate_status(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "kodi::gui::{} - invalid data", __func__); + return ADJUST_REFRESHRATE_STATUS_OFF; + } + + switch (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt( + CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE)) + { + case AdjustRefreshRate::ADJUST_REFRESHRATE_OFF: + return ADJUST_REFRESHRATE_STATUS_OFF; + break; + case AdjustRefreshRate::ADJUST_REFRESHRATE_ON_START: + return ADJUST_REFRESHRATE_STATUS_ON_START; + break; + case AdjustRefreshRate::ADJUST_REFRESHRATE_ON_STARTSTOP: + return ADJUST_REFRESHRATE_STATUS_ON_STARTSTOP; + break; + case AdjustRefreshRate::ADJUST_REFRESHRATE_ALWAYS: + return ADJUST_REFRESHRATE_STATUS_ALWAYS; + break; + default: + CLog::Log(LOGERROR, "kodi::gui::{} - Unhandled Adjust refresh rate setting", __func__); + return ADJUST_REFRESHRATE_STATUS_OFF; + break; + } +} + +//@} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/General.h b/xbmc/addons/interfaces/gui/General.h new file mode 100644 index 0000000..146d4f7 --- /dev/null +++ b/xbmc/addons/interfaces/gui/General.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/general.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/General.h" + */ + struct Interface_GUIGeneral + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note For add of new functions use the "_" style to identify direct a + * add-on callback function. Everything with CamelCase is only for the + * usage in Kodi only. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void lock(); + static void unlock(); + + static int get_screen_height(KODI_HANDLE kodiBase); + static int get_screen_width(KODI_HANDLE kodiBase); + static int get_video_resolution(KODI_HANDLE kodiBase); + static int get_current_window_dialog_id(KODI_HANDLE kodiBase); + static int get_current_window_id(KODI_HANDLE kodiBase); + static ADDON_HARDWARE_CONTEXT get_hw_context(KODI_HANDLE kodiBase); + static AdjustRefreshRateStatus get_adjust_refresh_rate_status(KODI_HANDLE kodiBase); + //@} + + private: + static int m_iAddonGUILockRef; + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/ListItem.cpp b/xbmc/addons/interfaces/gui/ListItem.cpp new file mode 100644 index 0000000..c91e451 --- /dev/null +++ b/xbmc/addons/interfaces/gui/ListItem.cpp @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ListItem.h" + +#include "FileItem.h" +#include "General.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/ListItem.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIListItem::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->listItem = new AddonToKodiFuncTable_kodi_gui_listItem(); + + addonInterface->toKodi->kodi_gui->listItem->create = create; + addonInterface->toKodi->kodi_gui->listItem->destroy = destroy; + addonInterface->toKodi->kodi_gui->listItem->get_label = get_label; + addonInterface->toKodi->kodi_gui->listItem->set_label = set_label; + addonInterface->toKodi->kodi_gui->listItem->get_label2 = get_label2; + addonInterface->toKodi->kodi_gui->listItem->set_label2 = set_label2; + addonInterface->toKodi->kodi_gui->listItem->get_art = get_art; + addonInterface->toKodi->kodi_gui->listItem->set_art = set_art; + addonInterface->toKodi->kodi_gui->listItem->get_path = get_path; + addonInterface->toKodi->kodi_gui->listItem->set_path = set_path; + addonInterface->toKodi->kodi_gui->listItem->get_property = get_property; + addonInterface->toKodi->kodi_gui->listItem->set_property = set_property; + addonInterface->toKodi->kodi_gui->listItem->select = select; + addonInterface->toKodi->kodi_gui->listItem->is_selected = is_selected; +} + +void Interface_GUIListItem::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->listItem; +} + +KODI_GUI_LISTITEM_HANDLE Interface_GUIListItem::create(KODI_HANDLE kodiBase, + const char* label, + const char* label2, + const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "ADDON::Interface_GUIListItem::{} - invalid data", __func__); + return nullptr; + } + + CFileItemPtr* item = new CFileItemPtr(new CFileItem()); + if (label) + item->get()->SetLabel(label); + if (label2) + item->get()->SetLabel2(label2); + if (path) + item->get()->SetPath(path); + + return item; +} + +void Interface_GUIListItem::destroy(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "ADDON::Interface_GUIListItem::{} - invalid data", __func__); + return; + } + + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (item) + delete item; +} + +char* Interface_GUIListItem::get_label(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return nullptr; + } + + char* ret; + Interface_GUIGeneral::lock(); + ret = strdup(item->get()->GetLabel().c_str()); + Interface_GUIGeneral::unlock(); + return ret; +} + +void Interface_GUIListItem::set_label(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return; + } + + Interface_GUIGeneral::lock(); + item->get()->SetLabel(label); + Interface_GUIGeneral::unlock(); +} + +char* Interface_GUIListItem::get_label2(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return nullptr; + } + + char* ret; + Interface_GUIGeneral::lock(); + ret = strdup(item->get()->GetLabel2().c_str()); + Interface_GUIGeneral::unlock(); + return ret; +} + +void Interface_GUIListItem::set_label2(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return; + } + + Interface_GUIGeneral::lock(); + item->get()->SetLabel2(label); + Interface_GUIGeneral::unlock(); +} + +char* Interface_GUIListItem::get_art(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* type) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item || !type) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', type='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(type), + addon ? addon->ID() : "unknown"); + return nullptr; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return nullptr; + } + + char* ret; + Interface_GUIGeneral::lock(); + ret = strdup(item->get()->GetArt(type).c_str()); + Interface_GUIGeneral::unlock(); + return ret; +} + +void Interface_GUIListItem::set_art(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* type, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item || !type || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}', type= " + "'{}', label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(type), + static_cast<const void*>(label), addon ? addon->ID() : "unknown"); + return; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return; + } + + Interface_GUIGeneral::lock(); + item->get()->SetArt(type, label); + Interface_GUIGeneral::unlock(); +} + +char* Interface_GUIListItem::get_path(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return nullptr; + } + + char* ret; + Interface_GUIGeneral::lock(); + ret = strdup(item->get()->GetPath().c_str()); + Interface_GUIGeneral::unlock(); + return ret; +} + + +void Interface_GUIListItem::set_path(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* path) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item || !path) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', path='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(path), + addon ? addon->ID() : "unknown"); + return; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return; + } + + Interface_GUIGeneral::lock(); + item->get()->SetPath(path); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIListItem::set_property(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* key, + const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item || !key || !value) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}', value='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + static_cast<const void*>(value), addon ? addon->ID() : "unknown"); + return; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + item->get()->SetProperty(lowerKey, CVariant(value)); + Interface_GUIGeneral::unlock(); +} + +char* Interface_GUIListItem::get_property(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* key) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return nullptr; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return nullptr; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + char* ret = strdup(item->get()->GetProperty(lowerKey).asString().c_str()); + Interface_GUIGeneral::unlock(); + + return ret; +} + +void Interface_GUIListItem::select(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + bool select) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return; + } + + Interface_GUIGeneral::lock(); + item->get()->Select(select); + Interface_GUIGeneral::unlock(); +} + +bool Interface_GUIListItem::is_selected(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CFileItemPtr* item = static_cast<CFileItemPtr*>(handle); + if (!addon || !item) + { + CLog::Log(LOGERROR, + "Interface_GUIListItem::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return false; + } + + if (item->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIListItem::{} - empty list item called on addon '{}'", + __func__, addon->ID()); + return false; + } + + Interface_GUIGeneral::lock(); + bool ret = item->get()->IsSelected(); + Interface_GUIGeneral::unlock(); + + return ret; +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/ListItem.h b/xbmc/addons/interfaces/gui/ListItem.h new file mode 100644 index 0000000..70e5c6a --- /dev/null +++ b/xbmc/addons/interfaces/gui/ListItem.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/list_item.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/ListItem.h" + */ + struct Interface_GUIListItem + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static KODI_GUI_LISTITEM_HANDLE create(KODI_HANDLE kodiBase, + const char* label, + const char* label2, + const char* path); + static void destroy(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + static char* get_label(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + static void set_label(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* label); + static char* get_label2(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + static void set_label2(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* label); + static char* get_art(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* type); + static void set_art(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* type, + const char* image); + static char* get_path(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + static void set_path(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* path); + static char* get_property(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* key); + static void set_property(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* key, + const char* value); + static void select(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, bool select); + static bool is_selected(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/Window.cpp b/xbmc/addons/interfaces/gui/Window.cpp new file mode 100644 index 0000000..307c339 --- /dev/null +++ b/xbmc/addons/interfaces/gui/Window.cpp @@ -0,0 +1,1499 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "addons/kodi-dev-kit/include/kodi/gui/Window.h" + +#include "FileItem.h" +#include "GUITranslator.h" +#include "General.h" +#include "ServiceBroker.h" +#include "Window.h" +#include "addons/Skin.h" +#include "addons/addoninfo/AddonInfo.h" +#include "addons/addoninfo/AddonType.h" +#include "addons/binary-addons/AddonDll.h" +#include "application/Application.h" +#include "controls/Rendering.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIRenderingControl.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/TextureManager.h" +#include "input/Key.h" +#include "messaging/ApplicationMessenger.h" +#include "utils/FileUtils.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIWindow::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->window = new AddonToKodiFuncTable_kodi_gui_window(); + + /* Window creation functions */ + addonInterface->toKodi->kodi_gui->window->create = create; + addonInterface->toKodi->kodi_gui->window->destroy = destroy; + addonInterface->toKodi->kodi_gui->window->set_callbacks = set_callbacks; + addonInterface->toKodi->kodi_gui->window->show = show; + addonInterface->toKodi->kodi_gui->window->close = close; + addonInterface->toKodi->kodi_gui->window->do_modal = do_modal; + + /* Window control functions */ + addonInterface->toKodi->kodi_gui->window->set_focus_id = set_focus_id; + addonInterface->toKodi->kodi_gui->window->get_focus_id = get_focus_id; + addonInterface->toKodi->kodi_gui->window->set_control_label = set_control_label; + addonInterface->toKodi->kodi_gui->window->set_control_visible = set_control_visible; + addonInterface->toKodi->kodi_gui->window->set_control_selected = set_control_selected; + + /* Window property functions */ + addonInterface->toKodi->kodi_gui->window->set_property = set_property; + addonInterface->toKodi->kodi_gui->window->set_property_int = set_property_int; + addonInterface->toKodi->kodi_gui->window->set_property_bool = set_property_bool; + addonInterface->toKodi->kodi_gui->window->set_property_double = set_property_double; + addonInterface->toKodi->kodi_gui->window->get_property = get_property; + addonInterface->toKodi->kodi_gui->window->get_property_int = get_property_int; + addonInterface->toKodi->kodi_gui->window->get_property_bool = get_property_bool; + addonInterface->toKodi->kodi_gui->window->get_property_double = get_property_double; + addonInterface->toKodi->kodi_gui->window->clear_properties = clear_properties; + addonInterface->toKodi->kodi_gui->window->clear_property = clear_property; + + /* List item functions */ + addonInterface->toKodi->kodi_gui->window->clear_item_list = clear_item_list; + addonInterface->toKodi->kodi_gui->window->add_list_item = add_list_item; + addonInterface->toKodi->kodi_gui->window->remove_list_item_from_position = + remove_list_item_from_position; + addonInterface->toKodi->kodi_gui->window->remove_list_item = remove_list_item; + addonInterface->toKodi->kodi_gui->window->get_list_item = get_list_item; + addonInterface->toKodi->kodi_gui->window->set_current_list_position = set_current_list_position; + addonInterface->toKodi->kodi_gui->window->get_current_list_position = get_current_list_position; + addonInterface->toKodi->kodi_gui->window->get_list_size = get_list_size; + addonInterface->toKodi->kodi_gui->window->set_container_property = set_container_property; + addonInterface->toKodi->kodi_gui->window->set_container_content = set_container_content; + addonInterface->toKodi->kodi_gui->window->get_current_container_id = get_current_container_id; + + /* Various functions */ + addonInterface->toKodi->kodi_gui->window->mark_dirty_region = mark_dirty_region; + + /* GUI control access functions */ + addonInterface->toKodi->kodi_gui->window->get_control_button = get_control_button; + addonInterface->toKodi->kodi_gui->window->get_control_edit = get_control_edit; + addonInterface->toKodi->kodi_gui->window->get_control_fade_label = get_control_fade_label; + addonInterface->toKodi->kodi_gui->window->get_control_image = get_control_image; + addonInterface->toKodi->kodi_gui->window->get_control_label = get_control_label; + addonInterface->toKodi->kodi_gui->window->get_control_progress = get_control_progress; + addonInterface->toKodi->kodi_gui->window->get_control_radio_button = get_control_radio_button; + addonInterface->toKodi->kodi_gui->window->get_control_render_addon = get_control_render_addon; + addonInterface->toKodi->kodi_gui->window->get_control_settings_slider = + get_control_settings_slider; + addonInterface->toKodi->kodi_gui->window->get_control_slider = get_control_slider; + addonInterface->toKodi->kodi_gui->window->get_control_spin = get_control_spin; + addonInterface->toKodi->kodi_gui->window->get_control_text_box = get_control_text_box; +} + +void Interface_GUIWindow::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->window; +} + +/*! + * Window creation functions + */ +//@{ +KODI_GUI_WINDOW_HANDLE Interface_GUIWindow::create(KODI_HANDLE kodiBase, + const char* xml_filename, + const char* default_skin, + bool as_dialog, + bool is_media) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon || !xml_filename || !default_skin) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (xml_filename='{}', " + "default_skin='{}') on addon '{}'", + __func__, static_cast<const void*>(xml_filename), + static_cast<const void*>(default_skin), addon ? addon->ID() : "unknown"); + return nullptr; + } + + if (as_dialog && is_media) + { + CLog::Log(LOGWARNING, + "Interface_GUIWindow::{}: {}/{} - addon tries to create dialog as media window who " + "not allowed, contact Developer '{}' of this addon", + __func__, CAddonInfo::TranslateType(addon->Type()), addon->Name(), addon->Author()); + } + + RESOLUTION_INFO res; + std::string strSkinPath = g_SkinInfo->GetSkinPath(xml_filename, &res); + + if (!CFileUtils::Exists(strSkinPath)) + { + std::string str("none"); + ADDON::AddonInfoPtr addonInfo = + std::make_shared<ADDON::CAddonInfo>(str, ADDON::AddonType::SKIN); + + // Check for the matching folder for the skin in the fallback skins folder + std::string fallbackPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "skins"); + std::string basePath = URIUtils::AddFileToFolder(fallbackPath, g_SkinInfo->ID()); + + strSkinPath = g_SkinInfo->GetSkinPath(xml_filename, &res, basePath); + + // Check for the matching folder for the skin in the fallback skins folder (if it exists) + if (CFileUtils::Exists(basePath)) + { + addonInfo->SetPath(basePath); + const std::shared_ptr<ADDON::CSkinInfo> skinInfo = + std::make_shared<ADDON::CSkinInfo>(addonInfo, res); + skinInfo->Start(); + strSkinPath = skinInfo->GetSkinPath(xml_filename, &res); + } + + if (!CFileUtils::Exists(strSkinPath)) + { + // Finally fallback to the DefaultSkin as it didn't exist in either the Kodi Skin folder or the fallback skin folder + addonInfo->SetPath(URIUtils::AddFileToFolder(fallbackPath, default_skin)); + const std::shared_ptr<ADDON::CSkinInfo> skinInfo = + std::make_shared<ADDON::CSkinInfo>(addonInfo, res); + + skinInfo->Start(); + strSkinPath = skinInfo->GetSkinPath(xml_filename, &res); + if (!CFileUtils::Exists(strSkinPath)) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{}: {}/{} - XML File '{}' for Window is missing, contact " + "Developer '{}' of this addon", + __func__, CAddonInfo::TranslateType(addon->Type()), addon->Name(), strSkinPath, + addon->Author()); + return nullptr; + } + } + } + + int id = GetNextAvailableWindowId(); + if (id < 0) + return nullptr; + + CGUIWindow* window; + if (!as_dialog) + window = new CGUIAddonWindow(id, strSkinPath, addon, is_media); + else + window = new CGUIAddonWindowDialog(id, strSkinPath, addon); + + Interface_GUIGeneral::lock(); + CServiceBroker::GetGUI()->GetWindowManager().Add(window); + Interface_GUIGeneral::unlock(); + + if (!CServiceBroker::GetGUI()->GetWindowManager().GetWindow(id)) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - Requested window id '{}' does not exist for addon '{}'", + __func__, id, addon->ID()); + delete window; + return nullptr; + } + window->SetCoordsRes(res); + return window; +} + +void Interface_GUIWindow::destroy(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + CGUIWindow* pWindow = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow(pAddonWindow->GetID()); + if (pWindow) + { + // first change to an existing window + if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == pAddonWindow->GetID() && + !g_application.m_bStop) + { + if (CServiceBroker::GetGUI()->GetWindowManager().GetWindow(pAddonWindow->m_oldWindowId)) + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->m_oldWindowId); + else // old window does not exist anymore, switch to home + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_HOME); + } + // Free any window properties + pAddonWindow->ClearProperties(); + // free the window's resources and unload it (free all guicontrols) + pAddonWindow->FreeResources(true); + + CServiceBroker::GetGUI()->GetWindowManager().Remove(pAddonWindow->GetID()); + } + delete pAddonWindow; + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::set_callbacks( + KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_CLIENT_HANDLE clienthandle, + bool (*CBOnInit)(KODI_GUI_CLIENT_HANDLE), + bool (*CBOnFocus)(KODI_GUI_CLIENT_HANDLE, int), + bool (*CBOnClick)(KODI_GUI_CLIENT_HANDLE, int), + bool (*CBOnAction)(KODI_GUI_CLIENT_HANDLE, ADDON_ACTION), + void (*CBGetContextButtons)(KODI_GUI_CLIENT_HANDLE, int, gui_context_menu_pair*, unsigned int*), + bool (*CBOnContextButton)(KODI_GUI_CLIENT_HANDLE, int, unsigned int)) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !clienthandle) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (handle='{}', clienthandle='{}') " + "on addon '{}'", + __func__, handle, clienthandle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->m_clientHandle = clienthandle; + pAddonWindow->CBOnInit = CBOnInit; + pAddonWindow->CBOnClick = CBOnClick; + pAddonWindow->CBOnFocus = CBOnFocus; + pAddonWindow->CBOnAction = CBOnAction; + pAddonWindow->CBGetContextButtons = CBGetContextButtons; + pAddonWindow->CBOnContextButton = CBOnContextButton; + Interface_GUIGeneral::unlock(); +} + +bool Interface_GUIWindow::show(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon ? addon->ID() : "unknown"); + return false; + } + + if (pAddonWindow->m_oldWindowId != pAddonWindow->m_windowId && + pAddonWindow->m_windowId != CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()) + pAddonWindow->m_oldWindowId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(); + + Interface_GUIGeneral::lock(); + if (pAddonWindow->IsDialog()) + dynamic_cast<CGUIAddonWindowDialog*>(pAddonWindow)->Show(true, false); + else + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->GetID()); + Interface_GUIGeneral::unlock(); + + return true; +} + +bool Interface_GUIWindow::close(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon ? addon->ID() : "unknown"); + return false; + } + + pAddonWindow->PulseActionEvent(); + + Interface_GUIGeneral::lock(); + + // if it's a dialog, we have to close it a bit different + if (pAddonWindow->IsDialog()) + dynamic_cast<CGUIAddonWindowDialog*>(pAddonWindow)->Show(false); + else + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->m_oldWindowId); + pAddonWindow->m_oldWindowId = 0; + + Interface_GUIGeneral::unlock(); + + return true; +} + +bool Interface_GUIWindow::do_modal(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon ? addon->ID() : "unknown"); + return false; + } + + if (pAddonWindow->GetID() == CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()) + return true; + + if (pAddonWindow->m_oldWindowId != pAddonWindow->m_windowId && + pAddonWindow->m_windowId != CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()) + pAddonWindow->m_oldWindowId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(); + + Interface_GUIGeneral::lock(); + if (pAddonWindow->IsDialog()) + dynamic_cast<CGUIAddonWindowDialog*>(pAddonWindow)->Show(true, true); + else + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->GetID()); + Interface_GUIGeneral::unlock(); + + return true; +} +//@} + +/*! + * Window control functions + */ +//@{ +bool Interface_GUIWindow::set_focus_id(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return false; + } + + if (!pAddonWindow->GetControl(control_id)) + { + CLog::Log(LOGERROR, "Interface_GUIWindow - {}: {} - Control does not exist in window", __func__, + addon->Name()); + return false; + } + + Interface_GUIGeneral::lock(); + CGUIMessage msg(GUI_MSG_SETFOCUS, pAddonWindow->m_windowId, control_id); + pAddonWindow->OnMessage(msg); + Interface_GUIGeneral::unlock(); + + return true; +} + +int Interface_GUIWindow::get_focus_id(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return -1; + } + + Interface_GUIGeneral::lock(); + int control_id = pAddonWindow->GetFocusedControlID(); + Interface_GUIGeneral::unlock(); + + if (control_id == -1) + CLog::Log(LOGERROR, "Interface_GUIWindow - {}: {} - No control in this window has focus", + __func__, addon->Name()); + + return control_id; +} + +void Interface_GUIWindow::set_control_label(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + CGUIMessage msg(GUI_MSG_LABEL_SET, pAddonWindow->m_windowId, control_id); + msg.SetLabel(label); + pAddonWindow->OnMessage(msg); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::set_control_visible(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + CGUIMessage msg(visible ? GUI_MSG_VISIBLE : GUI_MSG_HIDDEN, pAddonWindow->m_windowId, control_id); + pAddonWindow->OnMessage(msg); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::set_control_selected(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + bool selected) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + CGUIMessage msg(selected ? GUI_MSG_SET_SELECTED : GUI_MSG_SET_DESELECTED, + pAddonWindow->m_windowId, control_id); + pAddonWindow->OnMessage(msg); + Interface_GUIGeneral::unlock(); +} +//@} + +/*! + * Window property functions + */ +//@{ +void Interface_GUIWindow::set_property(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key || !value) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}', value='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + static_cast<const void*>(value), addon ? addon->ID() : "unknown"); + return; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + pAddonWindow->SetProperty(lowerKey, value); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::set_property_int(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + int value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + pAddonWindow->SetProperty(lowerKey, value); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::set_property_bool(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + bool value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + pAddonWindow->SetProperty(lowerKey, value); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::set_property_double(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + double value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + pAddonWindow->SetProperty(lowerKey, value); + Interface_GUIGeneral::unlock(); +} + +char* Interface_GUIWindow::get_property(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return nullptr; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + std::string value = pAddonWindow->GetProperty(lowerKey).asString(); + Interface_GUIGeneral::unlock(); + + return strdup(value.c_str()); +} + +int Interface_GUIWindow::get_property_int(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return -1; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + int value = static_cast<int>(pAddonWindow->GetProperty(lowerKey).asInteger()); + Interface_GUIGeneral::unlock(); + + return value; +} + +bool Interface_GUIWindow::get_property_bool(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return false; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + bool value = pAddonWindow->GetProperty(lowerKey).asBoolean(); + Interface_GUIGeneral::unlock(); + + return value; +} + +double Interface_GUIWindow::get_property_double(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return 0.0; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + double value = pAddonWindow->GetProperty(lowerKey).asDouble(); + Interface_GUIGeneral::unlock(); + + return value; +} + +void Interface_GUIWindow::clear_properties(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->ClearProperties(); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::clear_property(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + addon ? addon->ID() : "unknown"); + return; + } + + std::string lowerKey = key; + StringUtils::ToLower(lowerKey); + + Interface_GUIGeneral::lock(); + pAddonWindow->SetProperty(lowerKey, ""); + Interface_GUIGeneral::unlock(); +} +//@} + +/*! + * List item functions + */ +//@{ +void Interface_GUIWindow::clear_item_list(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->ClearList(); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::add_list_item(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_LISTITEM_HANDLE item, + int list_position) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !item) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "item='{}') on addon '{}'", + __func__, kodiBase, handle, item, addon ? addon->ID() : "unknown"); + return; + } + + CFileItemPtr* pItem(static_cast<CFileItemPtr*>(item)); + if (pItem->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIWindow::{} - empty list item called on addon '{}'", __func__, + addon->ID()); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->AddItem(pItem, list_position); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::remove_list_item_from_position(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->RemoveItem(list_position); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::remove_list_item(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_LISTITEM_HANDLE item) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !item) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "item='{}') on addon '{}'", + __func__, kodiBase, handle, item, addon ? addon->ID() : "unknown"); + return; + } + + CFileItemPtr* pItem(static_cast<CFileItemPtr*>(item)); + if (pItem->get() == nullptr) + { + CLog::Log(LOGERROR, "Interface_GUIWindow::{} - empty list item called on addon '{}'", __func__, + addon->ID()); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->RemoveItem(pItem); + Interface_GUIGeneral::unlock(); +} + +KODI_GUI_LISTITEM_HANDLE Interface_GUIWindow::get_list_item(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + Interface_GUIGeneral::lock(); + CFileItemPtr* pItem(pAddonWindow->GetListItem(list_position)); + if (pItem == nullptr || pItem->get() == nullptr) + { + CLog::Log(LOGERROR, "ADDON::Interface_GUIWindow - {}: {} - Index out of range", __func__, + addon->Name()); + + if (pItem) + { + delete pItem; + pItem = nullptr; + } + } + Interface_GUIGeneral::unlock(); + + return pItem; +} + +void Interface_GUIWindow::set_current_list_position(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->SetCurrentListPosition(list_position); + Interface_GUIGeneral::unlock(); +} + +int Interface_GUIWindow::get_current_list_position(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return -1; + } + + Interface_GUIGeneral::lock(); + int listPos = pAddonWindow->GetCurrentListPosition(); + Interface_GUIGeneral::unlock(); + + return listPos; +} + +int Interface_GUIWindow::get_list_size(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return -1; + } + + Interface_GUIGeneral::lock(); + int listSize = pAddonWindow->GetListSize(); + Interface_GUIGeneral::unlock(); + + return listSize; +} + +void Interface_GUIWindow::set_container_property(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !key || !value) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "key='{}', value='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(key), + static_cast<const void*>(value), addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->SetContainerProperty(key, value); + Interface_GUIGeneral::unlock(); +} + +void Interface_GUIWindow::set_container_content(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow || !value) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', " + "value='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(value), + addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->SetContainerContent(value); + Interface_GUIGeneral::unlock(); +} + +int Interface_GUIWindow::get_current_container_id(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return -1; + } + + Interface_GUIGeneral::lock(); + int id = pAddonWindow->GetCurrentContainerControlId(); + Interface_GUIGeneral::unlock(); + + return id; +} +//@} + +/*! + * Various functions + */ +//@{ +void Interface_GUIWindow::mark_dirty_region(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + pAddonWindow->MarkDirtyRegion(); + Interface_GUIGeneral::unlock(); +} +//@} + +/*! + * GUI control access functions + */ +//@{ +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_button(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_BUTTON, + "button"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_edit(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_EDIT, "edit"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_fade_label(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_FADELABEL, + "fade label"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_image(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_IMAGE, "image"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_label(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_LABEL, "label"); +} +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_progress(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_PROGRESS, + "progress"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_radio_button(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_RADIO, + "radio button"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_render_addon(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + CGUIControl* pGUIControl = static_cast<CGUIControl*>(GetControl( + kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_RENDERADDON, "renderaddon")); + if (!pGUIControl) + return nullptr; + + CGUIAddonRenderingControl* pRenderControl = + new CGUIAddonRenderingControl(dynamic_cast<CGUIRenderingControl*>(pGUIControl)); + return pRenderControl; +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_settings_slider( + KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_SETTINGS_SLIDER, + "settings slider"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_slider(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_SLIDER, + "slider"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_spin(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_SPINEX, "spin"); +} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_text_box(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id) +{ + return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_TEXTBOX, + "textbox"); +} +//@} + +KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::GetControl(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + const char* function, + CGUIControl::GUICONTROLTYPES type, + const std::string& typeName) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle); + if (!addon || !pAddonWindow) + { + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on " + "addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return pAddonWindow->GetAddonControl(control_id, type, typeName); +} + +int Interface_GUIWindow::GetNextAvailableWindowId() +{ + Interface_GUIGeneral::lock(); + + // if window WINDOW_ADDON_END is in use it means addon can't create more windows + if (CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_ADDON_END)) + { + Interface_GUIGeneral::unlock(); + CLog::Log(LOGERROR, + "Interface_GUIWindow::{} - Maximum number of windows for binary addons reached", + __func__); + return -1; + } + + // window id's WINDOW_ADDON_START - WINDOW_ADDON_END are reserved for addons + // get first window id that is not in use + int id = WINDOW_ADDON_START; + while (id < WINDOW_ADDON_END && + CServiceBroker::GetGUI()->GetWindowManager().GetWindow(id) != nullptr) + id++; + + Interface_GUIGeneral::unlock(); + return id; +} + +CGUIAddonWindow::CGUIAddonWindow(int id, const std::string& strXML, CAddonDll* addon, bool isMedia) + : CGUIMediaWindow(id, strXML.c_str()), + m_clientHandle{nullptr}, + CBOnInit{nullptr}, + CBOnFocus{nullptr}, + CBOnClick{nullptr}, + CBOnAction{nullptr}, + CBGetContextButtons{nullptr}, + CBOnContextButton{nullptr}, + m_windowId(id), + m_oldWindowId(0), + m_actionEvent(true), + m_addon(addon), + m_isMedia(isMedia) +{ + m_loadType = LOAD_ON_GUI_INIT; +} + +CGUIControl* CGUIAddonWindow::GetAddonControl(int controlId, + CGUIControl::GUICONTROLTYPES type, + const std::string& typeName) +{ + // Load window resources, if not already done, to have related xml content + // present and to let control find it + if (!m_windowLoaded) + { + if (!Initialize()) + { + CLog::Log(LOGERROR, + "CGUIAddonGUI_Window::{}: {} - Window initialize failed by control id '{}' request " + "for '{}'", + __func__, m_addon->Name(), controlId, typeName); + return nullptr; + } + } + + CGUIControl* pGUIControl = GetControl(controlId); + if (!pGUIControl) + { + CLog::Log(LOGERROR, + "CGUIAddonGUI_Window::{}: {} - Requested GUI control Id '{}' for '{}' not present!", + __func__, m_addon->Name(), controlId, typeName); + return nullptr; + } + else if (pGUIControl->GetControlType() != type) + { + CLog::Log(LOGERROR, + "CGUIAddonGUI_Window::{}: {} - Requested GUI control Id '{}' not the type '{}'!", + __func__, m_addon->Name(), controlId, typeName); + return nullptr; + } + + return pGUIControl; +} + +bool CGUIAddonWindow::OnAction(const CAction& action) +{ + // Let addon decide whether it wants to handle action first + if (CBOnAction && + CBOnAction(m_clientHandle, CAddonGUITranslator::TranslateActionIdToAddon(action.GetID()))) + return true; + + return CGUIWindow::OnAction(action); +} + +bool CGUIAddonWindow::OnMessage(CGUIMessage& message) +{ + switch (message.GetMessage()) + { + case GUI_MSG_WINDOW_DEINIT: + { + return CGUIMediaWindow::OnMessage(message); + } + break; + + case GUI_MSG_WINDOW_INIT: + { + CGUIMediaWindow::OnMessage(message); + + if (CBOnInit) + CBOnInit(m_clientHandle); + return true; + } + break; + + case GUI_MSG_FOCUSED: + { + if (m_viewControl.HasControl(message.GetControlId()) && + m_viewControl.GetCurrentControl() != message.GetControlId()) + { + m_viewControl.SetFocused(); + return true; + } + // check if our focused control is one of our category buttons + int iControl = message.GetControlId(); + if (CBOnFocus) + CBOnFocus(m_clientHandle, iControl); + } + break; + + case GUI_MSG_NOTIFY_ALL: + { + // most messages from GUI_MSG_NOTIFY_ALL break container content, whitelist working ones. + if (message.GetParam1() == GUI_MSG_PAGE_CHANGE || + message.GetParam1() == GUI_MSG_WINDOW_RESIZE) + return CGUIMediaWindow::OnMessage(message); + return true; + } + + case GUI_MSG_CLICKED: + { + int iControl = message.GetSenderId(); + if (iControl && iControl != this->GetID()) + { + CGUIControl* controlClicked = this->GetControl(iControl); + + // The old python way used to check list AND SELECITEM method or if its a button, checkmark. + // Its done this way for now to allow other controls without a python version like togglebutton to still raise a onAction event + if (controlClicked) // Will get problems if we the id is not on the window and we try to do GetControlType on it. So check to make sure it exists + { + if ((controlClicked->IsContainer() && (message.GetParam1() == ACTION_SELECT_ITEM || + message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)) || + !controlClicked->IsContainer()) + { + if (CBOnClick) + return CBOnClick(m_clientHandle, iControl); + } + else if (controlClicked->IsContainer() && + (message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK || + message.GetParam1() == ACTION_CONTEXT_MENU)) + { + if (CBOnAction) + { + // Check addon want to handle right click for a context menu, if + // not used from addon becomes "GetContextButtons(...)" called. + if (CBOnAction(m_clientHandle, ADDON_ACTION_CONTEXT_MENU)) + return true; + } + } + } + } + } + break; + } + + return CGUIMediaWindow::OnMessage(message); +} + +void CGUIAddonWindow::AllocResources(bool forceLoad /*= false */) +{ + std::string tmpDir = URIUtils::GetDirectory(GetProperty("xmlfile").asString()); + std::string fallbackMediaPath; + URIUtils::GetParentPath(tmpDir, fallbackMediaPath); + URIUtils::RemoveSlashAtEnd(fallbackMediaPath); + m_mediaDir = fallbackMediaPath; + + CServiceBroker::GetGUI()->GetTextureManager().AddTexturePath(m_mediaDir); + CGUIMediaWindow::AllocResources(forceLoad); + CServiceBroker::GetGUI()->GetTextureManager().RemoveTexturePath(m_mediaDir); +} + +void CGUIAddonWindow::Render() +{ + CServiceBroker::GetGUI()->GetTextureManager().AddTexturePath(m_mediaDir); + CGUIMediaWindow::Render(); + CServiceBroker::GetGUI()->GetTextureManager().RemoveTexturePath(m_mediaDir); +} + +void CGUIAddonWindow::AddItem(CFileItemPtr* fileItem, int itemPosition) +{ + if (itemPosition == -1 || itemPosition > m_vecItems->Size()) + { + m_vecItems->Add(*fileItem); + } + else if (itemPosition < -1 && !(itemPosition - 1 < m_vecItems->Size())) + { + m_vecItems->AddFront(*fileItem, 0); + } + else + { + m_vecItems->AddFront(*fileItem, itemPosition); + } + m_viewControl.SetItems(*m_vecItems); + UpdateButtons(); +} + +void CGUIAddonWindow::RemoveItem(int itemPosition) +{ + m_vecItems->Remove(itemPosition); + m_viewControl.SetItems(*m_vecItems); + UpdateButtons(); +} + +void CGUIAddonWindow::RemoveItem(CFileItemPtr* fileItem) +{ + m_vecItems->Remove(fileItem->get()); + m_viewControl.SetItems(*m_vecItems); + UpdateButtons(); +} + +int CGUIAddonWindow::GetCurrentListPosition() +{ + return m_viewControl.GetSelectedItem(); +} + +void CGUIAddonWindow::SetCurrentListPosition(int item) +{ + m_viewControl.SetSelectedItem(item); +} + +int CGUIAddonWindow::GetListSize() +{ + return m_vecItems->Size(); +} + +CFileItemPtr* CGUIAddonWindow::GetListItem(int position) +{ + if (position < 0 || position >= m_vecItems->Size()) + return nullptr; + return new CFileItemPtr(m_vecItems->Get(position)); +} + +void CGUIAddonWindow::ClearList() +{ + ClearFileItems(); + + m_viewControl.SetItems(*m_vecItems); + UpdateButtons(); +} + +void CGUIAddonWindow::SetContainerProperty(const std::string& key, const std::string& value) +{ + m_vecItems->SetProperty(key, value); +} + +void CGUIAddonWindow::SetContainerContent(const std::string& value) +{ + m_vecItems->SetContent(value); +} + +int CGUIAddonWindow::GetCurrentContainerControlId() +{ + return m_viewControl.GetCurrentControl(); +} + +void CGUIAddonWindow::GetContextButtons(int itemNumber, CContextButtons& buttons) +{ + gui_context_menu_pair c_buttons[ADDON_MAX_CONTEXT_ENTRIES] = {}; + unsigned int size = ADDON_MAX_CONTEXT_ENTRIES; + if (CBGetContextButtons) + { + CBGetContextButtons(m_clientHandle, itemNumber, c_buttons, &size); + for (unsigned int i = 0; i < size; ++i) + buttons.push_back(std::pair<unsigned int, std::string>(c_buttons[i].id, c_buttons[i].name)); + } +} + +bool CGUIAddonWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button) +{ + if (CBOnContextButton) + return CBOnContextButton(m_clientHandle, itemNumber, static_cast<unsigned int>(button)); + return false; +} + +void CGUIAddonWindow::WaitForActionEvent(unsigned int timeout) +{ + m_actionEvent.Wait(std::chrono::milliseconds(timeout)); + m_actionEvent.Reset(); +} + +void CGUIAddonWindow::PulseActionEvent() +{ + m_actionEvent.Set(); +} + +void CGUIAddonWindow::SetupShares() +{ + UpdateButtons(); +} + + +CGUIAddonWindowDialog::CGUIAddonWindowDialog(int id, const std::string& strXML, CAddonDll* addon) + : CGUIAddonWindow(id, strXML, addon, false), m_bRunning(false) +{ +} + +void CGUIAddonWindowDialog::Show(bool show /* = true */, bool modal /* = true*/) +{ + if (modal) + { + unsigned int count = CServiceBroker::GetWinSystem()->GetGfxContext().exit(); + CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_ADDON_DIALOG, 0, show ? 1 : 0, + static_cast<void*>(this)); + CServiceBroker::GetWinSystem()->GetGfxContext().restore(count); + } + else + CServiceBroker::GetAppMessenger()->PostMsg(TMSG_GUI_ADDON_DIALOG, 0, show ? 1 : 0, + static_cast<void*>(this)); +} + +void CGUIAddonWindowDialog::Show_Internal(bool show /* = true */) +{ + if (show) + { + m_bRunning = true; + CServiceBroker::GetGUI()->GetWindowManager().RegisterDialog(this); + + // activate this window... + CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, GetID()); + OnMessage(msg); + + // this dialog is derived from GUIMediaWindow + // make sure it is rendered last + m_renderOrder = RENDER_ORDER_DIALOG; + while (m_bRunning) + { + if (!ProcessRenderLoop(false)) + break; + } + } + else // hide + { + m_bRunning = false; + + CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0); + OnMessage(msg); + + CServiceBroker::GetGUI()->GetWindowManager().RemoveDialog(GetID()); + } +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/Window.h b/xbmc/addons/interfaces/gui/Window.h new file mode 100644 index 0000000..dad0737 --- /dev/null +++ b/xbmc/addons/interfaces/gui/Window.h @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/window.h" +#include "threads/Event.h" +#include "windows/GUIMediaWindow.h" + +extern "C" +{ + + struct AddonGlobalInterface; + struct gui_context_menu_pair; + + namespace ADDON + { + class CAddonDll; + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/Window.h" + */ + struct Interface_GUIWindow + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + /* Window creation functions */ + static KODI_GUI_WINDOW_HANDLE create(KODI_HANDLE kodiBase, + const char* xml_filename, + const char* default_skin, + bool as_dialog, + bool is_media); + static void destroy(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static void set_callbacks(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_CLIENT_HANDLE clienthandle, + bool (*CBInit)(KODI_GUI_CLIENT_HANDLE), + bool (*CBFocus)(KODI_GUI_CLIENT_HANDLE, int), + bool (*CBClick)(KODI_GUI_CLIENT_HANDLE, int), + bool (*CBOnAction)(KODI_GUI_CLIENT_HANDLE, ADDON_ACTION), + void (*CBGetContextButtons)(KODI_GUI_CLIENT_HANDLE, + int, + gui_context_menu_pair*, + unsigned int*), + bool (*CBOnContextButton)(KODI_GUI_CLIENT_HANDLE, int, unsigned int)); + static bool show(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static bool close(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static bool do_modal(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + + /* Window control functions */ + static bool set_focus_id(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + static int get_focus_id(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static void set_control_label(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + const char* label); + static void set_control_visible(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + bool visible); + static void set_control_selected(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + bool selected); + + /* Window property functions */ + static void set_property(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + const char* value); + static void set_property_int(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + int value); + static void set_property_bool(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + bool value); + static void set_property_double(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + double value); + static char* get_property(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, const char* key); + static int get_property_int(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key); + static bool get_property_bool(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key); + static double get_property_double(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key); + static void clear_properties(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static void clear_property(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key); + + /* List item functions */ + static void clear_item_list(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static void add_list_item(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_LISTITEM_HANDLE item, + int list_position); + static void remove_list_item_from_position(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position); + static void remove_list_item(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_LISTITEM_HANDLE item); + static KODI_GUI_LISTITEM_HANDLE get_list_item(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position); + static void set_current_list_position(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position); + static int get_current_list_position(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static int get_list_size(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + static void set_container_property(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + const char* value); + static void set_container_content(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* value); + static int get_current_container_id(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + + /* Various functions */ + static void mark_dirty_region(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + + /* GUI control access functions */ + static KODI_GUI_CONTROL_HANDLE get_control_button(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_edit(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_fade_label(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_image(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_label(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_radio_button(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_progress(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_render_addon(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_settings_slider(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_slider(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_spin(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + static KODI_GUI_CONTROL_HANDLE get_control_text_box(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id); + //@} + + private: + static KODI_GUI_CONTROL_HANDLE GetControl(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + const char* function, + CGUIControl::GUICONTROLTYPES type, + const std::string& typeName); + static int GetNextAvailableWindowId(); + }; + + class CGUIAddonWindow : public CGUIMediaWindow + { + friend struct Interface_GUIWindow; + + public: + CGUIAddonWindow(int id, const std::string& strXML, ADDON::CAddonDll* addon, bool isMedia); + ~CGUIAddonWindow() override = default; + + bool OnMessage(CGUIMessage& message) override; + bool OnAction(const CAction& action) override; + void AllocResources(bool forceLoad = false) override; + void Render() override; + bool IsMediaWindow() const override { return m_isMedia; } + + /* Addon to Kodi call functions */ + void PulseActionEvent(); + void AddItem(CFileItemPtr* fileItem, int itemPosition); + void RemoveItem(int itemPosition); + void RemoveItem(CFileItemPtr* fileItem); + void ClearList(); + CFileItemPtr* GetListItem(int position); + int GetListSize(); + int GetCurrentListPosition(); + void SetCurrentListPosition(int item); + void SetContainerProperty(const std::string& key, const std::string& value); + void SetContainerContent(const std::string& value); + int GetCurrentContainerControlId(); + CGUIControl* GetAddonControl(int controlId, + CGUIControl::GUICONTROLTYPES type, + const std::string& typeName); + + protected: + void GetContextButtons(int itemNumber, CContextButtons& buttons) override; + bool OnContextButton(int itemNumber, CONTEXT_BUTTON button) override; + void SetupShares() override; + + /* kodi to addon callback function addresses */ + KODI_GUI_CLIENT_HANDLE m_clientHandle; + bool (*CBOnInit)(KODI_GUI_CLIENT_HANDLE cbhdl); + bool (*CBOnFocus)(KODI_GUI_CLIENT_HANDLE cbhdl, int controlId); + bool (*CBOnClick)(KODI_GUI_CLIENT_HANDLE cbhdl, int controlId); + bool (*CBOnAction)(KODI_GUI_CLIENT_HANDLE cbhdl, ADDON_ACTION actionId); + void (*CBGetContextButtons)(KODI_GUI_CLIENT_HANDLE cbhdl, + int itemNumber, + gui_context_menu_pair* buttons, + unsigned int* size); + bool (*CBOnContextButton)(KODI_GUI_CLIENT_HANDLE cbhdl, int itemNumber, unsigned int button); + + const int m_windowId; + int m_oldWindowId; + + private: + void WaitForActionEvent(unsigned int timeout); + + CEvent m_actionEvent; + ADDON::CAddonDll* m_addon; + std::string m_mediaDir; + bool m_isMedia; + }; + + class CGUIAddonWindowDialog : public CGUIAddonWindow + { + public: + CGUIAddonWindowDialog(int id, const std::string& strXML, ADDON::CAddonDll* addon); + + bool IsDialogRunning() const override { return m_bRunning; } + bool IsDialog() const override { return true; } + bool IsModalDialog() const override { return true; } + + void Show(bool show = true, bool modal = true); + void Show_Internal(bool show = true); + + private: + bool m_bRunning; + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/Button.cpp b/xbmc/addons/interfaces/gui/controls/Button.cpp new file mode 100644 index 0000000..24a9994 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Button.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Button.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Button.h" +#include "guilib/GUIButtonControl.h" +#include "utils/StringUtils.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlButton::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_button = + new AddonToKodiFuncTable_kodi_gui_control_button(); + + addonInterface->toKodi->kodi_gui->control_button->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_button->set_enabled = set_enabled; + + addonInterface->toKodi->kodi_gui->control_button->set_label = set_label; + addonInterface->toKodi->kodi_gui->control_button->get_label = get_label; + + addonInterface->toKodi->kodi_gui->control_button->set_label2 = set_label2; + addonInterface->toKodi->kodi_gui->control_button->get_label2 = get_label2; +} + +void Interface_GUIControlButton::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_button; +} + +void Interface_GUIControlButton::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIButtonControl* control = static_cast<CGUIButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlButton::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlButton::set_enabled(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool enabled) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIButtonControl* control = static_cast<CGUIButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlButton::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetEnabled(enabled); +} + +void Interface_GUIControlButton::set_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIButtonControl* control = static_cast<CGUIButtonControl*>(handle); + if (!addon || !control || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIControlButton::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + control->SetLabel(label); +} + +char* Interface_GUIControlButton::get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIButtonControl* control = static_cast<CGUIButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlButton::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetLabel().c_str()); +} + +void Interface_GUIControlButton::set_label2(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIButtonControl* control = static_cast<CGUIButtonControl*>(handle); + if (!addon || !control || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIControlButton::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + control->SetLabel2(label); +} + +char* Interface_GUIControlButton::get_label2(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIButtonControl* control = static_cast<CGUIButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlButton::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetLabel2().c_str()); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Button.h b/xbmc/addons/interfaces/gui/controls/Button.h new file mode 100644 index 0000000..221ae4e --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Button.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/button.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Button.h" + */ + struct Interface_GUIControlButton + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_enabled(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + + static void set_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + static char* get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_label2(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + static char* get_label2(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/CMakeLists.txt b/xbmc/addons/interfaces/gui/controls/CMakeLists.txt new file mode 100644 index 0000000..0a708c6 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/CMakeLists.txt @@ -0,0 +1,27 @@ +set(SOURCES Button.cpp + Edit.cpp + FadeLabel.cpp + Image.cpp + Label.cpp + Progress.cpp + RadioButton.cpp + Rendering.cpp + SettingsSlider.cpp + Slider.cpp + Spin.cpp + TextBox.cpp) + +set(HEADERS Button.h + Edit.h + FadeLabel.h + Image.h + Label.h + Progress.h + RadioButton.h + Rendering.h + SettingsSlider.h + Slider.h + Spin.h + TextBox.h) + +core_add_library(addons_interfaces_gui_controls) diff --git a/xbmc/addons/interfaces/gui/controls/Edit.cpp b/xbmc/addons/interfaces/gui/controls/Edit.cpp new file mode 100644 index 0000000..b537279 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Edit.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Edit.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Edit.h" +#include "guilib/GUIEditControl.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlEdit::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_edit = new AddonToKodiFuncTable_kodi_gui_control_edit(); + + addonInterface->toKodi->kodi_gui->control_edit->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_edit->set_enabled = set_enabled; + addonInterface->toKodi->kodi_gui->control_edit->set_input_type = set_input_type; + addonInterface->toKodi->kodi_gui->control_edit->set_label = set_label; + addonInterface->toKodi->kodi_gui->control_edit->get_label = get_label; + addonInterface->toKodi->kodi_gui->control_edit->set_text = set_text; + addonInterface->toKodi->kodi_gui->control_edit->get_text = get_text; + addonInterface->toKodi->kodi_gui->control_edit->set_cursor_position = set_cursor_position; + addonInterface->toKodi->kodi_gui->control_edit->get_cursor_position = get_cursor_position; +} + +void Interface_GUIControlEdit::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_edit; +} + +void Interface_GUIControlEdit::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlEdit::set_enabled(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool enable) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetEnabled(enable); +} + +void Interface_GUIControlEdit::set_input_type(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int type, + const char* heading) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}', " + "heading='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(heading), + addon ? addon->ID() : "unknown"); + return; + } + + CGUIEditControl::INPUT_TYPE kodiType; + switch (static_cast<AddonGUIInputType>(type)) + { + case ADDON_INPUT_TYPE_TEXT: + kodiType = CGUIEditControl::INPUT_TYPE_TEXT; + break; + case ADDON_INPUT_TYPE_NUMBER: + kodiType = CGUIEditControl::INPUT_TYPE_NUMBER; + break; + case ADDON_INPUT_TYPE_SECONDS: + kodiType = CGUIEditControl::INPUT_TYPE_SECONDS; + break; + case ADDON_INPUT_TYPE_TIME: + kodiType = CGUIEditControl::INPUT_TYPE_TIME; + break; + case ADDON_INPUT_TYPE_DATE: + kodiType = CGUIEditControl::INPUT_TYPE_DATE; + break; + case ADDON_INPUT_TYPE_IPADDRESS: + kodiType = CGUIEditControl::INPUT_TYPE_IPADDRESS; + break; + case ADDON_INPUT_TYPE_PASSWORD: + kodiType = CGUIEditControl::INPUT_TYPE_PASSWORD; + break; + case ADDON_INPUT_TYPE_PASSWORD_MD5: + kodiType = CGUIEditControl::INPUT_TYPE_PASSWORD_MD5; + break; + case ADDON_INPUT_TYPE_SEARCH: + kodiType = CGUIEditControl::INPUT_TYPE_SEARCH; + break; + case ADDON_INPUT_TYPE_FILTER: + kodiType = CGUIEditControl::INPUT_TYPE_FILTER; + break; + case ADDON_INPUT_TYPE_READONLY: + default: + kodiType = CGUIEditControl::INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW; + } + + control->SetInputType(kodiType, heading); +} + +void Interface_GUIControlEdit::set_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + control->SetLabel(label); +} + +char* Interface_GUIControlEdit::get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetLabel().c_str()); +} + +void Interface_GUIControlEdit::set_text(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control || !text) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}', " + "text='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(text), + addon ? addon->ID() : "unknown"); + return; + } + + control->SetLabel2(text); +} + +char* Interface_GUIControlEdit::get_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetLabel2().c_str()); +} + +void Interface_GUIControlEdit::set_cursor_position(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + unsigned int position) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetCursorPosition(position); +} + +unsigned int Interface_GUIControlEdit::get_cursor_position(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIEditControl* control = static_cast<CGUIEditControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlEdit::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return 0; + } + + return control->GetCursorPosition(); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Edit.h b/xbmc/addons/interfaces/gui/controls/Edit.h new file mode 100644 index 0000000..9dda1e2 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Edit.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/edit.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Edit.h" + */ + struct Interface_GUIControlEdit + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_enabled(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + + static void set_input_type(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int type, + const char* heading); + + static void set_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + static char* get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + static char* get_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_cursor_position(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + unsigned int position); + static unsigned int get_cursor_position(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/FadeLabel.cpp b/xbmc/addons/interfaces/gui/controls/FadeLabel.cpp new file mode 100644 index 0000000..13c5604 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/FadeLabel.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FadeLabel.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/FadeLabel.h" +#include "guilib/GUIFadeLabelControl.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlFadeLabel::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_fade_label = + new AddonToKodiFuncTable_kodi_gui_control_fade_label(); + + addonInterface->toKodi->kodi_gui->control_fade_label->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_fade_label->add_label = add_label; + addonInterface->toKodi->kodi_gui->control_fade_label->get_label = get_label; + addonInterface->toKodi->kodi_gui->control_fade_label->set_scrolling = set_scrolling; + addonInterface->toKodi->kodi_gui->control_fade_label->reset = reset; +} + +void Interface_GUIControlFadeLabel::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_fade_label; +} + +void Interface_GUIControlFadeLabel::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIFadeLabelControl* control = static_cast<CGUIFadeLabelControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlFadeLabel::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlFadeLabel::add_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIFadeLabelControl* control = static_cast<CGUIFadeLabelControl*>(handle); + if (!addon || !control || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIControlFadeLabel::{} - invalid handler data (kodiBase='{}', " + "handle='{}', label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_ADD, control->GetParentID(), control->GetID()); + msg.SetLabel(label); + control->OnMessage(msg); +} + +char* Interface_GUIControlFadeLabel::get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIFadeLabelControl* control = static_cast<CGUIFadeLabelControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlFadeLabel::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, control->GetParentID(), control->GetID()); + control->OnMessage(msg); + std::string text = msg.GetLabel(); + return strdup(text.c_str()); +} + +void Interface_GUIControlFadeLabel::set_scrolling(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool scroll) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIFadeLabelControl* control = static_cast<CGUIFadeLabelControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlFadeLabel::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetScrolling(scroll); +} + +void Interface_GUIControlFadeLabel::reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIFadeLabelControl* control = static_cast<CGUIFadeLabelControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlFadeLabel::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_RESET, control->GetParentID(), control->GetID()); + control->OnMessage(msg); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/FadeLabel.h b/xbmc/addons/interfaces/gui/controls/FadeLabel.h new file mode 100644 index 0000000..2c3cd68 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/FadeLabel.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/fade_label.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/FadeLabel.h" + */ + struct Interface_GUIControlFadeLabel + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_enabled(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + static void set_selected(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool selected); + + static void add_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + static char* get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_scrolling(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool scroll); + static void reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/Image.cpp b/xbmc/addons/interfaces/gui/controls/Image.cpp new file mode 100644 index 0000000..88f368c --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Image.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Image.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Image.h" +#include "guilib/GUIImage.h" +#include "utils/log.h" + +using namespace KODI; + +namespace ADDON +{ + +void Interface_GUIControlImage::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_image = + new AddonToKodiFuncTable_kodi_gui_control_image(); + + addonInterface->toKodi->kodi_gui->control_image->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_image->set_filename = set_filename; + addonInterface->toKodi->kodi_gui->control_image->set_color_diffuse = set_color_diffuse; +} + +void Interface_GUIControlImage::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_image; +} + +void Interface_GUIControlImage::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIImage* control = static_cast<CGUIImage*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlImage::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlImage::set_filename(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* filename, + bool use_cache) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIImage* control = static_cast<CGUIImage*>(handle); + if (!addon || !control || !filename) + { + CLog::Log(LOGERROR, + "Interface_GUIControlImage::{} - invalid handler data (kodiBase='{}', handle='{}', " + "filename='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(filename), + addon ? addon->ID() : "unknown"); + return; + } + + control->SetFileName(filename, false, use_cache); +} + +void Interface_GUIControlImage::set_color_diffuse(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + uint32_t colorDiffuse) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIImage* control = static_cast<CGUIImage*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlImage::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetColorDiffuse(GUILIB::GUIINFO::CGUIInfoColor(colorDiffuse)); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Image.h b/xbmc/addons/interfaces/gui/controls/Image.h new file mode 100644 index 0000000..b12bece --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Image.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/image.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Image.h" + */ + struct Interface_GUIControlImage + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_filename(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* filename, + bool use_cache); + static void set_color_diffuse(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + uint32_t color_diffuse); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/Label.cpp b/xbmc/addons/interfaces/gui/controls/Label.cpp new file mode 100644 index 0000000..3922e3f --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Label.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Label.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Label.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUILabelControl.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlLabel::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_label = + new AddonToKodiFuncTable_kodi_gui_control_label(); + + addonInterface->toKodi->kodi_gui->control_label->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_label->set_label = set_label; + addonInterface->toKodi->kodi_gui->control_label->get_label = get_label; +} + +void Interface_GUIControlLabel::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_label; +} + +void Interface_GUIControlLabel::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUILabelControl* control = static_cast<CGUILabelControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlLabel::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlLabel::set_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUILabelControl* control = static_cast<CGUILabelControl*>(handle); + if (!addon || !control || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIControlLabel::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_SET, control->GetParentID(), control->GetID()); + msg.SetLabel(label); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +char* Interface_GUIControlLabel::get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUILabelControl* control = static_cast<CGUILabelControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlLabel::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetDescription().c_str()); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Label.h b/xbmc/addons/interfaces/gui/controls/Label.h new file mode 100644 index 0000000..020c3d5 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Label.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/label.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Label.h" + */ + struct Interface_GUIControlLabel + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + + static void set_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + static char* get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/Progress.cpp b/xbmc/addons/interfaces/gui/controls/Progress.cpp new file mode 100644 index 0000000..639d079 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Progress.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Progress.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Progress.h" +#include "guilib/GUIProgressControl.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlProgress::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_progress = + new AddonToKodiFuncTable_kodi_gui_control_progress(); + + addonInterface->toKodi->kodi_gui->control_progress->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_progress->set_percentage = set_percentage; + addonInterface->toKodi->kodi_gui->control_progress->get_percentage = get_percentage; +} + +void Interface_GUIControlProgress::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_progress; +} + +void Interface_GUIControlProgress::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIProgressControl* control = static_cast<CGUIProgressControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlProgress::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlProgress::set_percentage(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float percent) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIProgressControl* control = static_cast<CGUIProgressControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlProgress::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetPercentage(percent); +} + +float Interface_GUIControlProgress::get_percentage(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIProgressControl* control = static_cast<CGUIProgressControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlProgress::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return 0.0f; + } + + return control->GetPercentage(); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Progress.h b/xbmc/addons/interfaces/gui/controls/Progress.h new file mode 100644 index 0000000..c3368fa --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Progress.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/progress.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Progress.h" + */ + struct Interface_GUIControlProgress + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + + static void set_percentage(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float percent); + static float get_percentage(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/RadioButton.cpp b/xbmc/addons/interfaces/gui/controls/RadioButton.cpp new file mode 100644 index 0000000..9d3b826 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/RadioButton.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "RadioButton.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/RadioButton.h" +#include "guilib/GUIRadioButtonControl.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlRadioButton::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_radio_button = + new AddonToKodiFuncTable_kodi_gui_control_radio_button(); + + addonInterface->toKodi->kodi_gui->control_radio_button->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_radio_button->set_enabled = set_enabled; + + addonInterface->toKodi->kodi_gui->control_radio_button->set_label = set_label; + addonInterface->toKodi->kodi_gui->control_radio_button->get_label = get_label; + + addonInterface->toKodi->kodi_gui->control_radio_button->set_selected = set_selected; + addonInterface->toKodi->kodi_gui->control_radio_button->is_selected = is_selected; +} + +void Interface_GUIControlRadioButton::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_radio_button; +} + +void Interface_GUIControlRadioButton::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIRadioButtonControl* control = static_cast<CGUIRadioButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlRadioButton::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlRadioButton::set_enabled(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool enabled) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIRadioButtonControl* control = static_cast<CGUIRadioButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlRadioButton::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetEnabled(enabled); +} + +void Interface_GUIControlRadioButton::set_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIRadioButtonControl* control = static_cast<CGUIRadioButtonControl*>(handle); + if (!addon || !control || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIControlRadioButton::{} - invalid handler data (kodiBase='{}', " + "handle='{}', label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + control->SetLabel(label); +} + +char* Interface_GUIControlRadioButton::get_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIRadioButtonControl* control = static_cast<CGUIRadioButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlRadioButton::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetLabel().c_str()); +} + +void Interface_GUIControlRadioButton::set_selected(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool selected) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIRadioButtonControl* control = static_cast<CGUIRadioButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlRadioButton::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetSelected(selected); +} + +bool Interface_GUIControlRadioButton::is_selected(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIRadioButtonControl* control = static_cast<CGUIRadioButtonControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlRadioButton::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return false; + } + + return control->IsSelected(); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/RadioButton.h b/xbmc/addons/interfaces/gui/controls/RadioButton.h new file mode 100644 index 0000000..dd7ed4e --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/RadioButton.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/radio_button.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/RadioButton.h" + */ + struct Interface_GUIControlRadioButton + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_enabled(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + + static void set_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + static char* get_label(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_selected(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool selected); + static bool is_selected(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/Rendering.cpp b/xbmc/addons/interfaces/gui/controls/Rendering.cpp new file mode 100644 index 0000000..a26a27f --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Rendering.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Rendering.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/interfaces/gui/General.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Rendering.h" +#include "guilib/GUIRenderingControl.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlAddonRendering::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_rendering = + new AddonToKodiFuncTable_kodi_gui_control_rendering(); + + addonInterface->toKodi->kodi_gui->control_rendering->set_callbacks = set_callbacks; + addonInterface->toKodi->kodi_gui->control_rendering->destroy = destroy; +} + +void Interface_GUIControlAddonRendering::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_rendering; +} + +void Interface_GUIControlAddonRendering::set_callbacks( + KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + KODI_GUI_CLIENT_HANDLE clienthandle, + bool (*createCB)(KODI_GUI_CLIENT_HANDLE, int, int, int, int, ADDON_HARDWARE_CONTEXT), + void (*renderCB)(KODI_GUI_CLIENT_HANDLE), + void (*stopCB)(KODI_GUI_CLIENT_HANDLE), + bool (*dirtyCB)(KODI_GUI_CLIENT_HANDLE)) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonRenderingControl* control = static_cast<CGUIAddonRenderingControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlAddonRendering::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + control->m_clientHandle = clienthandle; + control->CBCreate = createCB; + control->CBRender = renderCB; + control->CBStop = stopCB; + control->CBDirty = dirtyCB; + control->m_addon = addon; + Interface_GUIGeneral::unlock(); + + control->m_control->InitCallback(control); +} + +void Interface_GUIControlAddonRendering::destroy(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUIAddonRenderingControl* control = static_cast<CGUIAddonRenderingControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlAddonRendering::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + Interface_GUIGeneral::lock(); + static_cast<CGUIAddonRenderingControl*>(handle)->Delete(); + Interface_GUIGeneral::unlock(); +} + + +CGUIAddonRenderingControl::CGUIAddonRenderingControl(CGUIRenderingControl* control) + : CBCreate{nullptr}, + CBRender{nullptr}, + CBStop{nullptr}, + CBDirty{nullptr}, + m_clientHandle{nullptr}, + m_addon{nullptr}, + m_control{control}, + m_refCount{1} +{ +} + +bool CGUIAddonRenderingControl::Create(int x, int y, int w, int h, void* device) +{ + if (CBCreate) + { + if (CBCreate(m_clientHandle, x, y, w, h, device)) + { + ++m_refCount; + return true; + } + } + return false; +} + +void CGUIAddonRenderingControl::Render() +{ + if (CBRender) + { + CBRender(m_clientHandle); + } +} + +void CGUIAddonRenderingControl::Stop() +{ + if (CBStop) + { + CBStop(m_clientHandle); + } + + --m_refCount; + if (m_refCount <= 0) + delete this; +} + +void CGUIAddonRenderingControl::Delete() +{ + --m_refCount; + if (m_refCount <= 0) + delete this; +} + +bool CGUIAddonRenderingControl::IsDirty() +{ + bool ret = true; + if (CBDirty) + { + ret = CBDirty(m_clientHandle); + } + return ret; +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Rendering.h b/xbmc/addons/interfaces/gui/controls/Rendering.h new file mode 100644 index 0000000..dbd82d8 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Rendering.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/rendering.h" +#include "guilib/IRenderingCallback.h" + +class CGUIRenderingControl; + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + class CAddonDll; + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Rendering.h" + */ + struct Interface_GUIControlAddonRendering + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_callbacks( + KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + KODI_GUI_CLIENT_HANDLE clienthandle, + bool (*createCB)(KODI_GUI_CLIENT_HANDLE, int, int, int, int, ADDON_HARDWARE_CONTEXT), + void (*renderCB)(KODI_GUI_CLIENT_HANDLE), + void (*stopCB)(KODI_GUI_CLIENT_HANDLE), + bool (*dirtyCB)(KODI_GUI_CLIENT_HANDLE)); + static void destroy(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + //@} + }; + + class CGUIAddonRenderingControl : public IRenderingCallback + { + friend struct Interface_GUIControlAddonRendering; + + public: + explicit CGUIAddonRenderingControl(CGUIRenderingControl* pControl); + ~CGUIAddonRenderingControl() override = default; + + bool Create(int x, int y, int w, int h, void* device) override; + void Render() override; + void Stop() override; + bool IsDirty() override; + virtual void Delete(); + + protected: + bool (*CBCreate)(KODI_GUI_CLIENT_HANDLE cbhdl, int x, int y, int w, int h, void* device); + void (*CBRender)(KODI_GUI_CLIENT_HANDLE cbhdl); + void (*CBStop)(KODI_GUI_CLIENT_HANDLE cbhdl); + bool (*CBDirty)(KODI_GUI_CLIENT_HANDLE cbhdl); + + KODI_GUI_CLIENT_HANDLE m_clientHandle; + CAddonDll* m_addon; + CGUIRenderingControl* m_control; + int m_refCount; + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/SettingsSlider.cpp b/xbmc/addons/interfaces/gui/controls/SettingsSlider.cpp new file mode 100644 index 0000000..c847a64 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/SettingsSlider.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "SettingsSlider.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/SettingsSlider.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUISettingsSliderControl.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlSettingsSlider::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_settings_slider = + new AddonToKodiFuncTable_kodi_gui_control_settings_slider(); + + addonInterface->toKodi->kodi_gui->control_settings_slider->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_settings_slider->set_enabled = set_enabled; + + addonInterface->toKodi->kodi_gui->control_settings_slider->set_text = set_text; + addonInterface->toKodi->kodi_gui->control_settings_slider->reset = reset; + + addonInterface->toKodi->kodi_gui->control_settings_slider->set_int_range = set_int_range; + addonInterface->toKodi->kodi_gui->control_settings_slider->set_int_value = set_int_value; + addonInterface->toKodi->kodi_gui->control_settings_slider->get_int_value = get_int_value; + addonInterface->toKodi->kodi_gui->control_settings_slider->set_int_interval = set_int_interval; + + addonInterface->toKodi->kodi_gui->control_settings_slider->set_percentage = set_percentage; + addonInterface->toKodi->kodi_gui->control_settings_slider->get_percentage = get_percentage; + + addonInterface->toKodi->kodi_gui->control_settings_slider->set_float_range = set_float_range; + addonInterface->toKodi->kodi_gui->control_settings_slider->set_float_value = set_float_value; + addonInterface->toKodi->kodi_gui->control_settings_slider->get_float_value = get_float_value; + addonInterface->toKodi->kodi_gui->control_settings_slider->set_float_interval = + set_float_interval; +} + +void Interface_GUIControlSettingsSlider::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_settings_slider; +} + +void Interface_GUIControlSettingsSlider::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlSettingsSlider::set_enabled(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool enabled) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetEnabled(enabled); +} + +void Interface_GUIControlSettingsSlider::set_text(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control || !text) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}', text='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(text), + addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_SET, control->GetParentID(), control->GetID()); + msg.SetLabel(text); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +void Interface_GUIControlSettingsSlider::reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_RESET, control->GetParentID(), control->GetID()); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +void Interface_GUIControlSettingsSlider::set_int_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int start, + int end) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_INT); + control->SetRange(start, end); +} + +void Interface_GUIControlSettingsSlider::set_int_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_INT); + control->SetIntValue(value); +} + +int Interface_GUIControlSettingsSlider::get_int_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return -1; + } + + return control->GetIntValue(); +} + +void Interface_GUIControlSettingsSlider::set_int_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int interval) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetIntInterval(interval); +} + +void Interface_GUIControlSettingsSlider::set_percentage(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float percent) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_PERCENTAGE); + control->SetPercentage(percent); +} + +float Interface_GUIControlSettingsSlider::get_percentage(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return 0.0f; + } + + return control->GetPercentage(); +} + +void Interface_GUIControlSettingsSlider::set_float_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_FLOAT); + control->SetFloatRange(start, end); +} + +void Interface_GUIControlSettingsSlider::set_float_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_FLOAT); + control->SetFloatValue(value); +} + +float Interface_GUIControlSettingsSlider::get_float_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return 0.0f; + } + + return control->GetFloatValue(); +} + +void Interface_GUIControlSettingsSlider::set_float_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISettingsSliderControl* control = static_cast<CGUISettingsSliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSettingsSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetFloatInterval(interval); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/SettingsSlider.h b/xbmc/addons/interfaces/gui/controls/SettingsSlider.h new file mode 100644 index 0000000..425c275 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/SettingsSlider.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/settings_slider.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/SettingsSlider.h" + */ + struct Interface_GUIControlSettingsSlider + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_enabled(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + + static void set_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + static void reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_int_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int start, + int end); + static void set_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int value); + static int get_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_int_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int interval); + + static void set_percentage(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float percent); + static float get_percentage(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_float_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end); + static void set_float_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float value); + static float get_float_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_float_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/Slider.cpp b/xbmc/addons/interfaces/gui/controls/Slider.cpp new file mode 100644 index 0000000..73502d8 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Slider.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Slider.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Slider.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUISliderControl.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlSlider::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_slider = + new AddonToKodiFuncTable_kodi_gui_control_slider(); + + addonInterface->toKodi->kodi_gui->control_slider->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_slider->set_enabled = set_enabled; + + addonInterface->toKodi->kodi_gui->control_slider->reset = reset; + addonInterface->toKodi->kodi_gui->control_slider->get_description = get_description; + + addonInterface->toKodi->kodi_gui->control_slider->set_int_range = set_int_range; + addonInterface->toKodi->kodi_gui->control_slider->set_int_value = set_int_value; + addonInterface->toKodi->kodi_gui->control_slider->get_int_value = get_int_value; + addonInterface->toKodi->kodi_gui->control_slider->set_int_interval = set_int_interval; + + addonInterface->toKodi->kodi_gui->control_slider->set_percentage = set_percentage; + addonInterface->toKodi->kodi_gui->control_slider->get_percentage = get_percentage; + + addonInterface->toKodi->kodi_gui->control_slider->set_float_range = set_float_range; + addonInterface->toKodi->kodi_gui->control_slider->set_float_value = set_float_value; + addonInterface->toKodi->kodi_gui->control_slider->get_float_value = get_float_value; + addonInterface->toKodi->kodi_gui->control_slider->set_float_interval = set_float_interval; +} + +void Interface_GUIControlSlider::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_slider; +} + +void Interface_GUIControlSlider::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlSlider::set_enabled(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool enabled) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetEnabled(enabled); +} + +void Interface_GUIControlSlider::reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_RESET, control->GetParentID(), control->GetID()); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +char* Interface_GUIControlSlider::get_description(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetDescription().c_str()); +} + +void Interface_GUIControlSlider::set_int_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int start, + int end) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_INT); + control->SetRange(start, end); +} + +void Interface_GUIControlSlider::set_int_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_INT); + control->SetIntValue(value); +} + +int Interface_GUIControlSlider::get_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return -1; + } + + return control->GetIntValue(); +} + +void Interface_GUIControlSlider::set_int_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int interval) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetIntInterval(interval); +} + +void Interface_GUIControlSlider::set_percentage(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float percent) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_PERCENTAGE); + control->SetPercentage(percent); +} + +float Interface_GUIControlSlider::get_percentage(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return 0.0f; + } + + return control->GetPercentage(); +} + +void Interface_GUIControlSlider::set_float_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_FLOAT); + control->SetFloatRange(start, end); +} + +void Interface_GUIControlSlider::set_float_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(SLIDER_CONTROL_TYPE_FLOAT); + control->SetFloatValue(value); +} + +float Interface_GUIControlSlider::get_float_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return 0.0f; + } + + return control->GetFloatValue(); +} + +void Interface_GUIControlSlider::set_float_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISliderControl* control = static_cast<CGUISliderControl*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSlider::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetFloatInterval(interval); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Slider.h b/xbmc/addons/interfaces/gui/controls/Slider.h new file mode 100644 index 0000000..30afbaf --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Slider.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/slider.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Slider.h" + */ + struct Interface_GUIControlSlider + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_enabled(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + + static void reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static char* get_description(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_int_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int start, + int end); + static void set_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int value); + static int get_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_int_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int interval); + + static void set_percentage(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float percent); + static float get_percentage(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_float_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end); + static void set_float_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float value); + static float get_float_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_float_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/Spin.cpp b/xbmc/addons/interfaces/gui/controls/Spin.cpp new file mode 100644 index 0000000..b9eb6ea --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Spin.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Spin.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/Spin.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUISpinControlEx.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlSpin::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_spin = new AddonToKodiFuncTable_kodi_gui_control_spin(); + + addonInterface->toKodi->kodi_gui->control_spin->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_spin->set_enabled = set_enabled; + + addonInterface->toKodi->kodi_gui->control_spin->set_text = set_text; + addonInterface->toKodi->kodi_gui->control_spin->reset = reset; + addonInterface->toKodi->kodi_gui->control_spin->set_type = set_type; + + addonInterface->toKodi->kodi_gui->control_spin->add_string_label = add_string_label; + addonInterface->toKodi->kodi_gui->control_spin->set_string_value = set_string_value; + addonInterface->toKodi->kodi_gui->control_spin->get_string_value = get_string_value; + + addonInterface->toKodi->kodi_gui->control_spin->add_int_label = add_int_label; + addonInterface->toKodi->kodi_gui->control_spin->set_int_range = set_int_range; + addonInterface->toKodi->kodi_gui->control_spin->set_int_value = set_int_value; + addonInterface->toKodi->kodi_gui->control_spin->get_int_value = get_int_value; + + addonInterface->toKodi->kodi_gui->control_spin->set_float_range = set_float_range; + addonInterface->toKodi->kodi_gui->control_spin->set_float_value = set_float_value; + addonInterface->toKodi->kodi_gui->control_spin->get_float_value = get_float_value; + addonInterface->toKodi->kodi_gui->control_spin->set_float_interval = set_float_interval; +} + +void Interface_GUIControlSpin::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_spin; +} + +void Interface_GUIControlSpin::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlSpin::set_enabled(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool enabled) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetEnabled(enabled); +} + +void Interface_GUIControlSpin::set_text(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control || !text) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}', " + "text='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(text), + addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_SET, control->GetParentID(), control->GetID()); + msg.SetLabel(text); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +void Interface_GUIControlSpin::reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_RESET, control->GetParentID(), control->GetID()); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +void Interface_GUIControlSpin::set_type(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int type) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetType(type); +} + +void Interface_GUIControlSpin::add_string_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label, + const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control || !label || !value) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}', value='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + static_cast<const void*>(value), addon ? addon->ID() : "unknown"); + return; + } + + control->AddLabel(std::string(label), std::string(value)); +} + +void Interface_GUIControlSpin::set_string_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control || !value) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}', " + "value='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(value), + addon ? addon->ID() : "unknown"); + return; + } + + control->SetStringValue(std::string(value)); +} + +char* Interface_GUIControlSpin::get_string_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetStringValue().c_str()); +} + +void Interface_GUIControlSpin::add_int_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label, + int value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control || !label) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}', " + "label='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(label), + addon ? addon->ID() : "unknown"); + return; + } + + control->AddLabel(std::string(label), value); +} + +void Interface_GUIControlSpin::set_int_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int start, + int end) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetRange(start, end); +} + +void Interface_GUIControlSpin::set_int_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetValue(value); +} + +int Interface_GUIControlSpin::get_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return -1; + } + + return control->GetValue(); +} + +void Interface_GUIControlSpin::set_float_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetFloatRange(start, end); +} + +void Interface_GUIControlSpin::set_float_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float value) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetFloatValue(value); +} + +float Interface_GUIControlSpin::get_float_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return 0.0f; + } + + return control->GetFloatValue(); +} + +void Interface_GUIControlSpin::set_float_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUISpinControlEx* control = static_cast<CGUISpinControlEx*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlSpin::{} - invalid handler data (kodiBase='{}', handle='{}') " + "on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetFloatInterval(interval); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/Spin.h b/xbmc/addons/interfaces/gui/controls/Spin.h new file mode 100644 index 0000000..1c7102e --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/Spin.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/spin.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Spin.h" + */ + struct Interface_GUIControlSpin + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void set_enabled(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + + static void set_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + static void reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_type(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int type); + + static void add_string_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label, + const char* value); + static void add_int_label(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label, + int value); + + static void set_string_value(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* value); + static char* get_string_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_int_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int start, + int end); + static void set_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int value); + static int get_int_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + + static void set_float_range(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end); + static void set_float_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float value); + static float get_float_value(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_float_interval(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/controls/TextBox.cpp b/xbmc/addons/interfaces/gui/controls/TextBox.cpp new file mode 100644 index 0000000..44c5f89 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/TextBox.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "TextBox.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/controls/TextBox.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUITextBox.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIControlTextBox::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->control_text_box = + new AddonToKodiFuncTable_kodi_gui_control_text_box(); + + addonInterface->toKodi->kodi_gui->control_text_box->set_visible = set_visible; + addonInterface->toKodi->kodi_gui->control_text_box->reset = reset; + addonInterface->toKodi->kodi_gui->control_text_box->set_text = set_text; + addonInterface->toKodi->kodi_gui->control_text_box->get_text = get_text; + addonInterface->toKodi->kodi_gui->control_text_box->scroll = scroll; + addonInterface->toKodi->kodi_gui->control_text_box->set_auto_scrolling = set_auto_scrolling; +} + +void Interface_GUIControlTextBox::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->control_text_box; +} + +void Interface_GUIControlTextBox::set_visible(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + bool visible) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUITextBox* control = static_cast<CGUITextBox*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlTextBox::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetVisible(visible); +} + +void Interface_GUIControlTextBox::reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUITextBox* control = static_cast<CGUITextBox*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlTextBox::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_RESET, control->GetParentID(), control->GetID()); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +void Interface_GUIControlTextBox::set_text(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUITextBox* control = static_cast<CGUITextBox*>(handle); + if (!addon || !control || !text) + { + CLog::Log(LOGERROR, + "Interface_GUIControlTextBox::{} - invalid handler data (kodiBase='{}', " + "handle='{}', text='{}') on addon '{}'", + __func__, kodiBase, handle, static_cast<const void*>(text), + addon ? addon->ID() : "unknown"); + return; + } + + CGUIMessage msg(GUI_MSG_LABEL_SET, control->GetParentID(), control->GetID()); + msg.SetLabel(text); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, control->GetParentID()); +} + +char* Interface_GUIControlTextBox::get_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUITextBox* control = static_cast<CGUITextBox*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlTextBox::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return nullptr; + } + + return strdup(control->GetDescription().c_str()); +} + +void Interface_GUIControlTextBox::scroll(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + unsigned int position) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUITextBox* control = static_cast<CGUITextBox*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlTextBox::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->Scroll(position); +} + +void Interface_GUIControlTextBox::set_auto_scrolling( + KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int delay, int time, int repeat) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + CGUITextBox* control = static_cast<CGUITextBox*>(handle); + if (!addon || !control) + { + CLog::Log(LOGERROR, + "Interface_GUIControlTextBox::{} - invalid handler data (kodiBase='{}', " + "handle='{}') on addon '{}'", + __func__, kodiBase, handle, addon ? addon->ID() : "unknown"); + return; + } + + control->SetAutoScrolling(delay, time, repeat); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/controls/TextBox.h b/xbmc/addons/interfaces/gui/controls/TextBox.h new file mode 100644 index 0000000..09c2ff4 --- /dev/null +++ b/xbmc/addons/interfaces/gui/controls/TextBox.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/controls/text_box.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold general gui functions and initialize also all other gui related types not + * related to a instance type and usable for every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/TextBox.h" + */ + struct Interface_GUIControlTextBox + { + + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void set_visible(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + static void reset(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void set_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + static char* get_text(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + static void scroll(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, unsigned int position); + static void set_auto_scrolling( + KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int delay, int time, int repeat); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/CMakeLists.txt b/xbmc/addons/interfaces/gui/dialogs/CMakeLists.txt new file mode 100644 index 0000000..4dad4e9 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/CMakeLists.txt @@ -0,0 +1,23 @@ +set(SOURCES ContextMenu.cpp + ExtendedProgressBar.cpp + FileBrowser.cpp + Keyboard.cpp + Numeric.cpp + OK.cpp + Progress.cpp + Select.cpp + TextViewer.cpp + YesNo.cpp) + +set(HEADERS ContextMenu.h + ExtendedProgressBar.h + FileBrowser.h + Keyboard.h + Numeric.h + OK.h + Progress.h + Select.h + TextViewer.h + YesNo.h) + +core_add_library(addons_interfaces_gui_dialogs) diff --git a/xbmc/addons/interfaces/gui/dialogs/ContextMenu.cpp b/xbmc/addons/interfaces/gui/dialogs/ContextMenu.cpp new file mode 100644 index 0000000..e0e5684 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/ContextMenu.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ContextMenu.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/ContextMenu.h" +#include "dialogs/GUIDialogContextMenu.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogContextMenu::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogContextMenu = + new AddonToKodiFuncTable_kodi_gui_dialogContextMenu(); + + addonInterface->toKodi->kodi_gui->dialogContextMenu->open = open; +} + +void Interface_GUIDialogContextMenu::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogContextMenu; +} + +int Interface_GUIDialogContextMenu::open(KODI_HANDLE kodiBase, + const char* heading, + const char* entries[], + unsigned int size) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogContextMenu::{} - invalid data", __func__); + return -1; + } + + CGUIDialogContextMenu* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogContextMenu>( + WINDOW_DIALOG_CONTEXT_MENU); + if (!heading || !entries || !dialog) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogContextMenu::{} - invalid handler data (heading='{}', " + "entries='{}', dialog='{}') on addon '{}'", + __func__, static_cast<const void*>(heading), static_cast<const void*>(entries), + kodiBase, addon->ID()); + return -1; + } + + CContextButtons choices; + for (unsigned int i = 0; i < size; ++i) + choices.Add(i, entries[i]); + + return dialog->Show(choices); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/ContextMenu.h b/xbmc/addons/interfaces/gui/dialogs/ContextMenu.h new file mode 100644 index 0000000..7b41a28 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/ContextMenu.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/context_menu.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ContextMenu.h" + */ + struct Interface_GUIDialogContextMenu + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static int open(KODI_HANDLE kodiBase, + const char* heading, + const char* entries[], + unsigned int size); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/ExtendedProgressBar.cpp b/xbmc/addons/interfaces/gui/dialogs/ExtendedProgressBar.cpp new file mode 100644 index 0000000..9e7f7a7 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/ExtendedProgressBar.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ExtendedProgressBar.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h" +#include "dialogs/GUIDialogExtendedProgressBar.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogExtendedProgress::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogExtendedProgress = + new AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress(); + + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->new_dialog = new_dialog; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->delete_dialog = delete_dialog; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->get_title = get_title; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->set_title = set_title; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->get_text = get_text; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->set_text = set_text; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->is_finished = is_finished; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->mark_finished = mark_finished; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->get_percentage = get_percentage; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->set_percentage = set_percentage; + addonInterface->toKodi->kodi_gui->dialogExtendedProgress->set_progress = set_progress; +} + +void Interface_GUIDialogExtendedProgress::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogExtendedProgress; +} + +KODI_GUI_HANDLE Interface_GUIDialogExtendedProgress::new_dialog(KODI_HANDLE kodiBase, + const char* title) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return nullptr; + } + + // setup the progress dialog + CGUIDialogExtendedProgressBar* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogExtendedProgressBar>( + WINDOW_DIALOG_EXT_PROGRESS); + if (!title || !dialog) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid handler data (title='{}', " + "dialog='{}') on addon '{}'", + __func__, static_cast<const void*>(title), static_cast<void*>(dialog), addon->ID()); + return nullptr; + } + + CGUIDialogProgressBarHandle* dlgProgressHandle = dialog->GetHandle(title); + return dlgProgressHandle; +} + +void Interface_GUIDialogExtendedProgress::delete_dialog(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid handler data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgressBarHandle*>(handle)->MarkFinished(); +} + +char* Interface_GUIDialogExtendedProgress::get_title(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return nullptr; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid handler data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return nullptr; + } + + return strdup(static_cast<CGUIDialogProgressBarHandle*>(handle)->Title().c_str()); +} + +void Interface_GUIDialogExtendedProgress::set_title(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + const char* title) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return; + } + + if (!handle || !title) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid handler data (handle='{}', " + "title='{}') on addon '{}'", + __func__, handle, static_cast<const void*>(title), addon->ID()); + return; + } + + static_cast<CGUIDialogProgressBarHandle*>(handle)->SetTitle(title); +} + +char* Interface_GUIDialogExtendedProgress::get_text(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return nullptr; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid add-on data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return nullptr; + } + + return strdup(static_cast<CGUIDialogProgressBarHandle*>(handle)->Text().c_str()); +} + +void Interface_GUIDialogExtendedProgress::set_text(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return; + } + + if (!handle || !text) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid handler data (handle='{}', " + "text='{}') on addon '{}'", + __func__, handle, static_cast<const void*>(text), addon->ID()); + return; + } + + static_cast<CGUIDialogProgressBarHandle*>(handle)->SetText(text); +} + +bool Interface_GUIDialogExtendedProgress::is_finished(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return false; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid add-on data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return false; + } + + return static_cast<CGUIDialogProgressBarHandle*>(handle)->IsFinished(); +} + +void Interface_GUIDialogExtendedProgress::mark_finished(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid add-on data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgressBarHandle*>(handle)->MarkFinished(); +} + +float Interface_GUIDialogExtendedProgress::get_percentage(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return 0.0f; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid add-on data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return 0.0f; + } + + return static_cast<CGUIDialogProgressBarHandle*>(handle)->Percentage(); +} + +void Interface_GUIDialogExtendedProgress::set_percentage(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + float percentage) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid add-on data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgressBarHandle*>(handle)->SetPercentage(percentage); +} + +void Interface_GUIDialogExtendedProgress::set_progress(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + int currentItem, + int itemCount) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogExtendedProgress::{} - invalid kodi base data", + __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogExtendedProgress::{} - invalid add-on data (handle='{}') on " + "addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgressBarHandle*>(handle)->SetProgress(currentItem, itemCount); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/ExtendedProgressBar.h b/xbmc/addons/interfaces/gui/dialogs/ExtendedProgressBar.h new file mode 100644 index 0000000..66ccb49 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/ExtendedProgressBar.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/extended_progress.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h" + */ + struct Interface_GUIDialogExtendedProgress + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static KODI_GUI_HANDLE new_dialog(KODI_HANDLE kodiBase, const char* title); + static void delete_dialog(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static char* get_title(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void set_title(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, const char* title); + static char* get_text(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void set_text(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, const char* text); + static bool is_finished(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void mark_finished(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static float get_percentage(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void set_percentage(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, float percentage); + static void set_progress(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + int currentItem, + int itemCount); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/FileBrowser.cpp b/xbmc/addons/interfaces/gui/dialogs/FileBrowser.cpp new file mode 100644 index 0000000..84d6443 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/FileBrowser.cpp @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileBrowser.h" + +#include "URL.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/FileBrowser.h" +#include "dialogs/GUIDialogFileBrowser.h" +#include "settings/MediaSourceSettings.h" +#include "storage/MediaManager.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogFileBrowser::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogFileBrowser = + new AddonToKodiFuncTable_kodi_gui_dialogFileBrowser(); + + addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_directory = + show_and_get_directory; + addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file = show_and_get_file; + addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_from_dir = + show_and_get_file_from_dir; + addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_list = + show_and_get_file_list; + addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_source = show_and_get_source; + addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image = show_and_get_image; + addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image_list = + show_and_get_image_list; + addonInterface->toKodi->kodi_gui->dialogFileBrowser->clear_file_list = clear_file_list; +} + +void Interface_GUIDialogFileBrowser::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogFileBrowser; +} + +bool Interface_GUIDialogFileBrowser::show_and_get_directory(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + const char* path_in, + char** path_out, + bool write_only) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return false; + } + + if (!shares || !heading || !path_in || !path_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', " + "heading='{}', path_in='{}', path_out='{}') on addon '{}'", + __func__, static_cast<const void*>(shares), static_cast<const void*>(heading), + static_cast<const void*>(path_in), static_cast<void*>(path_out), addon->ID()); + return false; + } + + std::string strPath = path_in; + + VECSOURCES vecShares; + GetVECShares(vecShares, shares, strPath); + bool bRet = CGUIDialogFileBrowser::ShowAndGetDirectory(vecShares, heading, strPath, write_only); + if (bRet) + *path_out = strdup(strPath.c_str()); + return bRet; +} + +bool Interface_GUIDialogFileBrowser::show_and_get_file(KODI_HANDLE kodiBase, + const char* shares, + const char* mask, + const char* heading, + const char* path_in, + char** path_out, + bool use_thumbs, + bool use_file_directories) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return false; + } + + if (!shares || !mask || !heading || !path_in || !path_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', mask='{}', " + "heading='{}', path_in='{}', path_out='{}') on addon '{}'", + __func__, static_cast<const void*>(shares), static_cast<const void*>(mask), + static_cast<const void*>(heading), static_cast<const void*>(path_in), + static_cast<void*>(path_out), addon->ID()); + return false; + } + + std::string strPath = path_in; + + VECSOURCES vecShares; + GetVECShares(vecShares, shares, strPath); + bool bRet = CGUIDialogFileBrowser::ShowAndGetFile(vecShares, mask, heading, strPath, use_thumbs, + use_file_directories); + if (bRet) + *path_out = strdup(strPath.c_str()); + return bRet; +} + +bool Interface_GUIDialogFileBrowser::show_and_get_file_from_dir(KODI_HANDLE kodiBase, + const char* directory, + const char* mask, + const char* heading, + const char* path_in, + char** path_out, + bool use_thumbs, + bool use_file_directories, + bool single_list) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return false; + } + + if (!directory || !mask || !heading || !path_in || !path_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (directory='{}', " + "mask='{}', heading='{}', path_in='{}', path_out='{}') on addon '{}'", + __func__, static_cast<const void*>(directory), static_cast<const void*>(mask), + static_cast<const void*>(heading), static_cast<const void*>(path_in), + static_cast<void*>(path_out), addon->ID()); + return false; + } + + std::string strPath = path_in; + bool bRet = CGUIDialogFileBrowser::ShowAndGetFile(directory, mask, heading, strPath, use_thumbs, + use_file_directories, single_list); + if (bRet) + *path_out = strdup(strPath.c_str()); + return bRet; +} + +bool Interface_GUIDialogFileBrowser::show_and_get_file_list(KODI_HANDLE kodiBase, + const char* shares, + const char* mask, + const char* heading, + char*** file_list, + unsigned int* entries, + bool use_thumbs, + bool use_file_directories) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return false; + } + + if (!shares || !mask || !heading || !file_list || !entries) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', mask='{}', " + "heading='{}', file_list='{}', entries='{}') on addon '{}'", + __func__, static_cast<const void*>(shares), static_cast<const void*>(mask), + static_cast<const void*>(heading), static_cast<void*>(file_list), + static_cast<void*>(entries), addon->ID()); + return false; + } + + VECSOURCES vecShares; + GetVECShares(vecShares, shares, ""); + + std::vector<std::string> pathsInt; + bool bRet = CGUIDialogFileBrowser::ShowAndGetFileList(vecShares, mask, heading, pathsInt, + use_thumbs, use_file_directories); + if (bRet) + { + *entries = pathsInt.size(); + *file_list = static_cast<char**>(malloc(*entries * sizeof(char*))); + for (unsigned int i = 0; i < *entries; ++i) + (*file_list)[i] = strdup(pathsInt[i].c_str()); + } + else + *entries = 0; + return bRet; +} + +bool Interface_GUIDialogFileBrowser::show_and_get_source(KODI_HANDLE kodiBase, + const char* path_in, + char** path_out, + bool allowNetworkShares, + const char* additionalShare, + const char* strType) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return false; + } + + if (!strType || !additionalShare || !path_in || !path_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (additionalShare='{}', " + "strType='{}', path_in='{}', path_out='{}') on addon '{}'", + __func__, static_cast<const void*>(additionalShare), + static_cast<const void*>(strType), static_cast<const void*>(path_in), + static_cast<void*>(path_out), addon->ID()); + return false; + } + + std::string strPath = path_in; + + VECSOURCES vecShares; + if (additionalShare) + GetVECShares(vecShares, additionalShare, strPath); + bool bRet = + CGUIDialogFileBrowser::ShowAndGetSource(strPath, allowNetworkShares, &vecShares, strType); + if (bRet) + *path_out = strdup(strPath.c_str()); + return bRet; +} + +bool Interface_GUIDialogFileBrowser::show_and_get_image(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + const char* path_in, + char** path_out) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return false; + } + + if (!shares || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', " + "heading='{}') on addon '{}'", + __func__, static_cast<const void*>(shares), static_cast<const void*>(heading), + addon->ID()); + return false; + } + + std::string strPath = path_in; + + VECSOURCES vecShares; + GetVECShares(vecShares, shares, strPath); + bool bRet = CGUIDialogFileBrowser::ShowAndGetImage(vecShares, heading, strPath); + if (bRet) + *path_out = strdup(strPath.c_str()); + return bRet; +} + +bool Interface_GUIDialogFileBrowser::show_and_get_image_list(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + char*** file_list, + unsigned int* entries) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return false; + } + + if (!shares || !heading || !file_list || !entries) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', " + "heading='{}', file_list='{}', entries='{}') on addon '{}'", + __func__, static_cast<const void*>(shares), static_cast<const void*>(heading), + static_cast<void*>(file_list), static_cast<void*>(entries), addon->ID()); + return false; + } + + VECSOURCES vecShares; + GetVECShares(vecShares, shares, ""); + + std::vector<std::string> pathsInt; + bool bRet = CGUIDialogFileBrowser::ShowAndGetImageList(vecShares, heading, pathsInt); + if (bRet) + { + *entries = pathsInt.size(); + *file_list = static_cast<char**>(malloc(*entries * sizeof(char*))); + for (unsigned int i = 0; i < *entries; ++i) + (*file_list)[i] = strdup(pathsInt[i].c_str()); + } + else + *entries = 0; + return bRet; +} + +void Interface_GUIDialogFileBrowser::clear_file_list(KODI_HANDLE kodiBase, + char*** file_list, + unsigned int entries) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__); + return; + } + + if (*file_list) + { + for (unsigned int i = 0; i < entries; ++i) + free((*file_list)[i]); + free(*file_list); + *file_list = nullptr; + } + else + { + + CLog::Log(LOGERROR, + "Interface_GUIDialogFileBrowser::{} - invalid handler data (file_list='{}') on " + "addon '{}'", + __func__, static_cast<void*>(file_list), addon->ID()); + } +} + +void Interface_GUIDialogFileBrowser::GetVECShares(VECSOURCES& vecShares, + const std::string& strShares, + const std::string& strPath) +{ + std::size_t found; + found = strShares.find("local"); + if (found != std::string::npos) + CServiceBroker::GetMediaManager().GetLocalDrives(vecShares); + found = strShares.find("network"); + if (found != std::string::npos) + CServiceBroker::GetMediaManager().GetNetworkLocations(vecShares); + found = strShares.find("removable"); + if (found != std::string::npos) + CServiceBroker::GetMediaManager().GetRemovableDrives(vecShares); + found = strShares.find("programs"); + if (found != std::string::npos) + { + VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("programs"); + if (sources != nullptr) + vecShares.insert(vecShares.end(), sources->begin(), sources->end()); + } + found = strShares.find("files"); + if (found != std::string::npos) + { + VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("files"); + if (sources != nullptr) + vecShares.insert(vecShares.end(), sources->begin(), sources->end()); + } + found = strShares.find("music"); + if (found != std::string::npos) + { + VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("music"); + if (sources != nullptr) + vecShares.insert(vecShares.end(), sources->begin(), sources->end()); + } + found = strShares.find("video"); + if (found != std::string::npos) + { + VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("video"); + if (sources != nullptr) + vecShares.insert(vecShares.end(), sources->begin(), sources->end()); + } + found = strShares.find("pictures"); + if (found != std::string::npos) + { + VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("pictures"); + if (sources != nullptr) + vecShares.insert(vecShares.end(), sources->begin(), sources->end()); + } + + if (vecShares.empty()) + { + CMediaSource share; + std::string basePath = strPath; + std::string tempPath; + while (URIUtils::GetParentPath(basePath, tempPath)) + basePath = tempPath; + share.strPath = basePath; + // don't include the user details in the share name + CURL url(share.strPath); + share.strName = url.GetWithoutUserDetails(); + vecShares.push_back(share); + } +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/FileBrowser.h b/xbmc/addons/interfaces/gui/dialogs/FileBrowser.h new file mode 100644 index 0000000..c2193f3 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/FileBrowser.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/filebrowser.h" + +#include <string> +#include <vector> + +class CMediaSource; + +typedef std::vector<CMediaSource> VECSOURCES; + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/FileBrowser.h" + */ + struct Interface_GUIDialogFileBrowser + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static bool show_and_get_directory(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + const char* path_in, + char** path_out, + bool write_only); + + static bool show_and_get_file(KODI_HANDLE kodiBase, + const char* shares, + const char* mask, + const char* heading, + const char* path_in, + char** path_out, + bool use_thumbs, + bool use_file_directories); + + static bool show_and_get_file_from_dir(KODI_HANDLE kodiBase, + const char* directory, + const char* mask, + const char* heading, + const char* path_in, + char** path_out, + bool use_thumbs, + bool use_file_directories, + bool singleList); + + static bool show_and_get_file_list(KODI_HANDLE kodiBase, + const char* shares, + const char* mask, + const char* heading, + char*** file_list, + unsigned int* entries, + bool use_thumbs, + bool use_file_directories); + + static bool show_and_get_source(KODI_HANDLE kodiBase, + const char* path_in, + char** path_out, + bool allow_network_shares, + const char* additional_share, + const char* type); + + static bool show_and_get_image(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + const char* path_in, + char** path_out); + + static bool show_and_get_image_list(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + char*** file_list, + unsigned int* entries); + + static void clear_file_list(KODI_HANDLE kodiBase, char*** file_list, unsigned int entries); + //@} + + private: + static void GetVECShares(VECSOURCES& vecShares, + const std::string& strShares, + const std::string& strPath); + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Keyboard.cpp b/xbmc/addons/interfaces/gui/dialogs/Keyboard.cpp new file mode 100644 index 0000000..7ec56ab --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Keyboard.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Keyboard.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/Keyboard.h" +#include "guilib/GUIKeyboardFactory.h" +#include "utils/Variant.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogKeyboard::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogKeyboard = + new AddonToKodiFuncTable_kodi_gui_dialogKeyboard(); + + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_get_input_with_head = + show_and_get_input_with_head; + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_get_input = show_and_get_input; + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_get_new_password_with_head = + show_and_get_new_password_with_head; + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_get_new_password = + show_and_get_new_password; + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_new_password_with_head = + show_and_verify_new_password_with_head; + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_new_password = + show_and_verify_new_password; + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_password = + show_and_verify_password; + addonInterface->toKodi->kodi_gui->dialogKeyboard->show_and_get_filter = show_and_get_filter; + addonInterface->toKodi->kodi_gui->dialogKeyboard->send_text_to_active_keyboard = + send_text_to_active_keyboard; + addonInterface->toKodi->kodi_gui->dialogKeyboard->is_keyboard_activated = is_keyboard_activated; +} + +void Interface_GUIDialogKeyboard::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogKeyboard; +} + +bool Interface_GUIDialogKeyboard::show_and_get_input_with_head(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + const char* heading, + bool allow_empty_result, + bool hidden_input, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!text_in || !text_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (text_in='{}', " + "text_out='{}', heading='{}') on addon '{}'", + __func__, static_cast<const void*>(text_in), static_cast<void*>(text_out), + static_cast<const void*>(heading), addon->ID()); + return false; + } + + std::string str = text_in; + bool bRet = CGUIKeyboardFactory::ShowAndGetInput(str, CVariant{heading}, allow_empty_result, + hidden_input, auto_close_ms); + if (bRet) + *text_out = strdup(str.c_str()); + return bRet; +} + +bool Interface_GUIDialogKeyboard::show_and_get_input(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + bool allow_empty_result, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!text_in || !text_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (text_in='{}', " + "text_out='{}') on addon '{}'", + __func__, static_cast<const void*>(text_in), static_cast<void*>(text_out), + addon->ID()); + return false; + } + + std::string str = text_in; + bool bRet = CGUIKeyboardFactory::ShowAndGetInput(str, allow_empty_result, auto_close_ms); + if (bRet) + *text_out = strdup(str.c_str()); + return bRet; +} + +bool Interface_GUIDialogKeyboard::show_and_get_new_password_with_head(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + const char* heading, + bool allow_empty_result, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!password_in || !password_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (password_in='{}', " + "password_out='{}', heading='{}') on addon '{}'", + __func__, static_cast<const void*>(password_in), static_cast<void*>(password_out), + static_cast<const void*>(heading), addon->ID()); + return false; + } + + std::string str = password_in; + bool bRet = + CGUIKeyboardFactory::ShowAndGetNewPassword(str, heading, allow_empty_result, auto_close_ms); + if (bRet) + *password_out = strdup(str.c_str()); + return bRet; +} + +bool Interface_GUIDialogKeyboard::show_and_get_new_password(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!password_in || !password_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (password_in='{}', " + "password_out='{}') on addon '{}'", + __func__, static_cast<const void*>(password_in), static_cast<void*>(password_out), + addon->ID()); + return false; + } + + std::string str = password_in; + bool bRet = CGUIKeyboardFactory::ShowAndGetNewPassword(str, auto_close_ms); + if (bRet) + *password_out = strdup(str.c_str()); + return bRet; +} + +bool Interface_GUIDialogKeyboard::show_and_verify_new_password_with_head(KODI_HANDLE kodiBase, + char** password_out, + const char* heading, + bool allowEmpty, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!password_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (password_out='{}', " + "heading='{}') on addon '{}'", + __func__, static_cast<void*>(password_out), static_cast<const void*>(heading), + addon->ID()); + return false; + } + + std::string str; + bool bRet = + CGUIKeyboardFactory::ShowAndVerifyNewPassword(str, heading, allowEmpty, auto_close_ms); + if (bRet) + *password_out = strdup(str.c_str()); + return bRet; +} + +bool Interface_GUIDialogKeyboard::show_and_verify_new_password(KODI_HANDLE kodiBase, + char** password_out, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!password_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (password_out='{}') on " + "addon '{}'", + __func__, static_cast<void*>(password_out), addon->ID()); + return false; + } + + std::string str; + bool bRet = CGUIKeyboardFactory::ShowAndVerifyNewPassword(str, auto_close_ms); + if (bRet) + *password_out = strdup(str.c_str()); + return bRet; +} + +int Interface_GUIDialogKeyboard::show_and_verify_password(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + const char* heading, + int retries, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!password_in || !password_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (password_in='{}', " + "password_out='{}', heading='{}') on addon '{}'", + __func__, static_cast<const void*>(password_in), static_cast<void*>(password_out), + static_cast<const void*>(heading), addon->ID()); + return false; + } + + std::string str = password_in; + int iRet = CGUIKeyboardFactory::ShowAndVerifyPassword(str, heading, retries, auto_close_ms); + if (iRet) + *password_out = strdup(str.c_str()); + return iRet; +} + +bool Interface_GUIDialogKeyboard::show_and_get_filter(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + bool searching, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + if (!text_in || !text_out) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogKeyboard::{} - invalid handler data (text_in='{}', " + "text_out='{}') on addon '{}'", + __func__, static_cast<const void*>(text_in), static_cast<void*>(text_out), + addon->ID()); + return false; + } + + + std::string str = text_in; + bool bRet = CGUIKeyboardFactory::ShowAndGetFilter(str, searching, auto_close_ms); + if (bRet) + *text_out = strdup(str.c_str()); + return bRet; +} + +bool Interface_GUIDialogKeyboard::send_text_to_active_keyboard(KODI_HANDLE kodiBase, + const char* text, + bool close_keyboard) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + return CGUIKeyboardFactory::SendTextToActiveKeyboard(text, close_keyboard); +} + +bool Interface_GUIDialogKeyboard::is_keyboard_activated(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogKeyboard::{} - invalid data", __func__); + return false; + } + + return CGUIKeyboardFactory::isKeyboardActivated(); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Keyboard.h b/xbmc/addons/interfaces/gui/dialogs/Keyboard.h new file mode 100644 index 0000000..fb7d6b9 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Keyboard.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/keyboard.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Keyboard.h" + */ + struct Interface_GUIDialogKeyboard + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static bool show_and_get_input_with_head(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + const char* heading, + bool allow_empty_result, + bool hidden_input, + unsigned int auto_close_ms); + static bool show_and_get_input(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + bool allow_empty_result, + unsigned int auto_close_ms); + static bool show_and_get_new_password_with_head(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + const char* heading, + bool allow_empty_result, + unsigned int auto_close_ms); + static bool show_and_get_new_password(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + unsigned int auto_close_ms); + static bool show_and_verify_new_password_with_head(KODI_HANDLE kodiBase, + char** password_out, + const char* heading, + bool allowEmpty, + unsigned int auto_close_ms); + static bool show_and_verify_new_password(KODI_HANDLE kodiBase, + char** password_out, + unsigned int auto_close_ms); + static int show_and_verify_password(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + const char* heading, + int retries, + unsigned int auto_close_ms); + static bool show_and_get_filter(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + bool searching, + unsigned int auto_close_ms); + static bool send_text_to_active_keyboard(KODI_HANDLE kodiBase, + const char* text, + bool close_keyboard); + static bool is_keyboard_activated(KODI_HANDLE kodiBase); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp new file mode 100644 index 0000000..a78aa4a --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Numeric.h" + +#include "XBDateTime.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/Numeric.h" +#include "dialogs/GUIDialogNumeric.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogNumeric::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogNumeric = + new AddonToKodiFuncTable_kodi_gui_dialogNumeric(); + + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_verify_new_password = + show_and_verify_new_password; + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_verify_password = + show_and_verify_password; + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_verify_input = show_and_verify_input; + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_get_time = show_and_get_time; + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_get_date = show_and_get_date; + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_get_ip_address = + show_and_get_ip_address; + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_get_number = show_and_get_number; + addonInterface->toKodi->kodi_gui->dialogNumeric->show_and_get_seconds = show_and_get_seconds; +} + +void Interface_GUIDialogNumeric::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogNumeric; +} + +bool Interface_GUIDialogNumeric::show_and_verify_new_password(KODI_HANDLE kodiBase, char** password) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return false; + } + + std::string str; + bool bRet = CGUIDialogNumeric::ShowAndVerifyNewPassword(str); + if (bRet) + *password = strdup(str.c_str()); + return bRet; +} + +int Interface_GUIDialogNumeric::show_and_verify_password(KODI_HANDLE kodiBase, + const char* password, + const char* heading, + int retries) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return -1; + } + + if (!password || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogNumeric::{} - invalid handler data (password='{}', heading='{}') " + "on addon '{}'", + __func__, static_cast<const void*>(password), static_cast<const void*>(heading), + addon->ID()); + return -1; + } + + std::string pw(password); + return CGUIDialogNumeric::ShowAndVerifyPassword(pw, heading, retries); +} + +bool Interface_GUIDialogNumeric::show_and_verify_input(KODI_HANDLE kodiBase, + const char* verify_in, + char** verify_out, + const char* heading, + bool verify_input) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return false; + } + + if (!verify_in || !verify_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogNumeric::{} - invalid handler data (verify_in='{}', " + "verify_out='{}', heading='{}') on addon '{}'", + __func__, static_cast<const void*>(verify_in), static_cast<void*>(verify_out), + static_cast<const void*>(heading), addon->ID()); + return false; + } + + std::string str = verify_in; + if (CGUIDialogNumeric::ShowAndVerifyInput(str, heading, verify_input) == + InputVerificationResult::SUCCESS) + { + *verify_out = strdup(str.c_str()); + return true; + } + return false; +} + +bool Interface_GUIDialogNumeric::show_and_get_time(KODI_HANDLE kodiBase, + tm* time, + const char* heading) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return false; + } + + if (!time || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogNumeric::{} - invalid handler data (time='{}', heading='{}') on " + "addon '{}'", + __func__, static_cast<void*>(time), static_cast<const void*>(heading), addon->ID()); + return false; + } + + KODI::TIME::SystemTime systemTime; + CDateTime dateTime(*time); + dateTime.GetAsSystemTime(systemTime); + if (CGUIDialogNumeric::ShowAndGetTime(systemTime, heading)) + { + dateTime = systemTime; + dateTime.GetAsTm(*time); + return true; + } + return false; +} + +bool Interface_GUIDialogNumeric::show_and_get_date(KODI_HANDLE kodiBase, + tm* date, + const char* heading) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return false; + } + + if (!date || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogNumeric::{} - invalid handler data (date='{}', heading='{}') on " + "addon '{}'", + __func__, static_cast<void*>(date), static_cast<const void*>(heading), addon->ID()); + return false; + } + + KODI::TIME::SystemTime systemTime; + CDateTime dateTime(*date); + dateTime.GetAsSystemTime(systemTime); + if (CGUIDialogNumeric::ShowAndGetDate(systemTime, heading)) + { + dateTime = systemTime; + dateTime.GetAsTm(*date); + return true; + } + return false; +} + +bool Interface_GUIDialogNumeric::show_and_get_ip_address(KODI_HANDLE kodiBase, + const char* ip_address_in, + char** ip_address_out, + const char* heading) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return false; + } + + if (!ip_address_in || !ip_address_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogNumeric::{} - invalid handler data (ip_address_in='{}', " + "ip_address_out='{}', heading='{}') on addon '{}'", + __func__, static_cast<const void*>(ip_address_in), static_cast<void*>(ip_address_out), + static_cast<const void*>(heading), addon->ID()); + return false; + } + + std::string strIP = ip_address_in; + bool bRet = CGUIDialogNumeric::ShowAndGetIPAddress(strIP, heading); + if (bRet) + *ip_address_out = strdup(strIP.c_str()); + return bRet; +} + +bool Interface_GUIDialogNumeric::show_and_get_number(KODI_HANDLE kodiBase, + const char* number_in, + char** number_out, + const char* heading, + unsigned int auto_close_ms) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return false; + } + + if (!number_in || !number_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogNumeric::{} - invalid handler data (number_in='{}', " + "number_out='{}', heading='{}') on addon '{}'", + __func__, static_cast<const void*>(number_in), static_cast<void*>(number_out), + static_cast<const void*>(heading), addon->ID()); + return false; + } + + std::string str = number_in; + bool bRet = CGUIDialogNumeric::ShowAndGetNumber(str, heading, auto_close_ms); + if (bRet) + *number_out = strdup(str.c_str()); + return bRet; +} + +bool Interface_GUIDialogNumeric::show_and_get_seconds(KODI_HANDLE kodiBase, + const char* time_in, + char** time_out, + const char* heading) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogNumeric::{} - invalid data", __func__); + return false; + } + + if (!time_in || !time_out || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogNumeric::{} - invalid handler data (time_in='{}', time_out='{}', " + "heading='{}') on addon '{}'", + __func__, static_cast<const void*>(time_in), static_cast<void*>(time_out), + static_cast<const void*>(heading), addon->ID()); + return false; + } + + std::string str = time_in; + bool bRet = CGUIDialogNumeric::ShowAndGetSeconds(str, heading); + if (bRet) + *time_out = strdup(str.c_str()); + return bRet; +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Numeric.h b/xbmc/addons/interfaces/gui/dialogs/Numeric.h new file mode 100644 index 0000000..a54ad52 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Numeric.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/numeric.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Numeric.h" + */ + struct Interface_GUIDialogNumeric + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static bool show_and_verify_new_password(KODI_HANDLE kodiBase, char** password); + static int show_and_verify_password(KODI_HANDLE kodiBase, + const char* password, + const char* heading, + int retries); + static bool show_and_verify_input(KODI_HANDLE kodiBase, + const char* verify_in, + char** verify_out, + const char* heading, + bool verify_input); + static bool show_and_get_time(KODI_HANDLE kodiBase, tm* time, const char* heading); + static bool show_and_get_date(KODI_HANDLE kodiBase, tm* date, const char* heading); + static bool show_and_get_ip_address(KODI_HANDLE kodiBase, + const char* ip_address_in, + char** ip_address_out, + const char* heading); + static bool show_and_get_number(KODI_HANDLE kodiBase, + const char* number_in, + char** number_out, + const char* heading, + unsigned int auto_close_ms); + static bool show_and_get_seconds(KODI_HANDLE kodiBase, + const char* time_in, + char** time_out, + const char* heading); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/OK.cpp b/xbmc/addons/interfaces/gui/dialogs/OK.cpp new file mode 100644 index 0000000..90e9d69 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/OK.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "OK.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/OK.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "utils/Variant.h" +#include "utils/log.h" + +using namespace KODI::MESSAGING; + +namespace ADDON +{ + +void Interface_GUIDialogOK::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogOK = new AddonToKodiFuncTable_kodi_gui_dialogOK(); + + addonInterface->toKodi->kodi_gui->dialogOK->show_and_get_input_single_text = + show_and_get_input_single_text; + addonInterface->toKodi->kodi_gui->dialogOK->show_and_get_input_line_text = + show_and_get_input_line_text; +} + +void Interface_GUIDialogOK::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogOK; +} + +void Interface_GUIDialogOK::show_and_get_input_single_text(KODI_HANDLE kodiBase, + const char* heading, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon || !heading || !text) + { + CLog::Log( + LOGERROR, "Interface_GUIDialogOK:{} - invalid data (addon='{}', heading='{}', text='{}')", + __func__, kodiBase, static_cast<const void*>(heading), static_cast<const void*>(text)); + return; + } + + HELPERS::ShowOKDialogText(CVariant{heading}, CVariant{text}); +} + +void Interface_GUIDialogOK::show_and_get_input_line_text(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon || !heading || !line0 || !line1 || !line2) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogOK::{} - invalid data (addon='{}', heading='{}', line0='{}', " + "line1='{}', line2='{}')", + __func__, kodiBase, static_cast<const void*>(heading), + static_cast<const void*>(line0), static_cast<const void*>(line1), + static_cast<const void*>(line2)); + return; + } + HELPERS::ShowOKDialogLines(CVariant{heading}, CVariant{line0}, CVariant{line1}, CVariant{line2}); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/OK.h b/xbmc/addons/interfaces/gui/dialogs/OK.h new file mode 100644 index 0000000..fd13719 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/OK.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/ok.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/OK.h" + */ + struct Interface_GUIDialogOK + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note For add of new functions use the "_" style to identify direct a + * add-on callback function. Everything with CamelCase is only for the + * usage in Kodi only. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void show_and_get_input_single_text(KODI_HANDLE kodiBase, + const char* heading, + const char* text); + static void show_and_get_input_line_text(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Progress.cpp b/xbmc/addons/interfaces/gui/dialogs/Progress.cpp new file mode 100644 index 0000000..ff6c742 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Progress.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Progress.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/Progress.h" +#include "dialogs/GUIDialogProgress.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "utils/Variant.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogProgress::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogProgress = + new AddonToKodiFuncTable_kodi_gui_dialogProgress(); + + addonInterface->toKodi->kodi_gui->dialogProgress->new_dialog = new_dialog; + addonInterface->toKodi->kodi_gui->dialogProgress->delete_dialog = delete_dialog; + addonInterface->toKodi->kodi_gui->dialogProgress->open = open; + addonInterface->toKodi->kodi_gui->dialogProgress->set_heading = set_heading; + addonInterface->toKodi->kodi_gui->dialogProgress->set_line = set_line; + addonInterface->toKodi->kodi_gui->dialogProgress->set_can_cancel = set_can_cancel; + addonInterface->toKodi->kodi_gui->dialogProgress->is_canceled = is_canceled; + addonInterface->toKodi->kodi_gui->dialogProgress->set_percentage = set_percentage; + addonInterface->toKodi->kodi_gui->dialogProgress->get_percentage = get_percentage; + addonInterface->toKodi->kodi_gui->dialogProgress->show_progress_bar = show_progress_bar; + addonInterface->toKodi->kodi_gui->dialogProgress->set_progress_max = set_progress_max; + addonInterface->toKodi->kodi_gui->dialogProgress->set_progress_advance = set_progress_advance; + addonInterface->toKodi->kodi_gui->dialogProgress->abort = abort; +} + +void Interface_GUIDialogProgress::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogProgress; +} + +KODI_GUI_HANDLE Interface_GUIDialogProgress::new_dialog(KODI_HANDLE kodiBase) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return nullptr; + } + + CGUIDialogProgress* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>( + WINDOW_DIALOG_PROGRESS); + if (!dialog) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (dialog='{}') on addon '{}'", + __func__, static_cast<void*>(dialog), addon->ID()); + return nullptr; + } + + return dialog; +} + +void Interface_GUIDialogProgress::delete_dialog(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->Close(); +} + +void Interface_GUIDialogProgress::open(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->Open(); +} + +void Interface_GUIDialogProgress::set_heading(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + const char* heading) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle || !heading) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}', heading='{}') " + "on addon '{}'", + __func__, handle, static_cast<const void*>(heading), addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->SetHeading(heading); +} + +void Interface_GUIDialogProgress::set_line(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + unsigned int line, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle || !text) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}', text='{}') on " + "addon '{}'", + __func__, handle, static_cast<const void*>(text), addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->SetLine(line, text); +} + +void Interface_GUIDialogProgress::set_can_cancel(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + bool canCancel) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->SetCanCancel(canCancel); +} + +bool Interface_GUIDialogProgress::is_canceled(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return false; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return false; + } + + return static_cast<CGUIDialogProgress*>(handle)->IsCanceled(); +} + +void Interface_GUIDialogProgress::set_percentage(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + int percentage) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->SetPercentage(percentage); +} + +int Interface_GUIDialogProgress::get_percentage(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return 0; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return 0; + } + + return static_cast<CGUIDialogProgress*>(handle)->GetPercentage(); +} + +void Interface_GUIDialogProgress::show_progress_bar(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + bool onOff) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->ShowProgressBar(onOff); +} + +void Interface_GUIDialogProgress::set_progress_max(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + int max) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->SetProgressMax(max); +} + +void Interface_GUIDialogProgress::set_progress_advance(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + int nSteps) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return; + } + + static_cast<CGUIDialogProgress*>(handle)->SetProgressAdvance(nSteps); +} + +bool Interface_GUIDialogProgress::abort(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogProgress::{} - invalid data", __func__); + return false; + } + + if (!handle) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogProgress::{} - invalid handler data (handle='{}') on addon '{}'", + __func__, handle, addon->ID()); + return false; + } + + return static_cast<CGUIDialogProgress*>(handle)->Abort(); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Progress.h b/xbmc/addons/interfaces/gui/dialogs/Progress.h new file mode 100644 index 0000000..ba31f3c --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Progress.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/progress.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Progress.h" + */ + struct Interface_GUIDialogProgress + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static KODI_GUI_HANDLE new_dialog(KODI_HANDLE kodiBase); + static void delete_dialog(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void open(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void set_heading(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, const char* heading); + static void set_line(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + unsigned int line, + const char* text); + static void set_can_cancel(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, bool canCancel); + static bool is_canceled(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void set_percentage(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, int percentage); + static int get_percentage(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + static void show_progress_bar(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, bool bOnOff); + static void set_progress_max(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, int max); + static void set_progress_advance(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, int nSteps); + static bool abort(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Select.cpp b/xbmc/addons/interfaces/gui/dialogs/Select.cpp new file mode 100644 index 0000000..7ad6ed6 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Select.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Select.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/Select.h" +#include "dialogs/GUIDialogSelect.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "utils/Variant.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogSelect::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogSelect = new AddonToKodiFuncTable_kodi_gui_dialogSelect(); + + addonInterface->toKodi->kodi_gui->dialogSelect->open = open; + addonInterface->toKodi->kodi_gui->dialogSelect->open_multi_select = open_multi_select; +} + +void Interface_GUIDialogSelect::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogSelect; +} + +int Interface_GUIDialogSelect::open(KODI_HANDLE kodiBase, + const char* heading, + const char* entries[], + unsigned int size, + int selected, + unsigned int autoclose) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogSelect::{} - invalid data", __func__); + return -1; + } + + CGUIDialogSelect* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( + WINDOW_DIALOG_SELECT); + if (!heading || !entries || !dialog) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogSelect::{} - invalid handler data (heading='{}', entries='{}', " + "dialog='{}') on addon '{}'", + __func__, static_cast<const void*>(heading), static_cast<const void*>(entries), + static_cast<void*>(dialog), addon->ID()); + return -1; + } + + dialog->Reset(); + dialog->SetHeading(CVariant{heading}); + + for (unsigned int i = 0; i < size; ++i) + dialog->Add(entries[i]); + + if (selected > 0) + dialog->SetSelected(selected); + if (autoclose > 0) + dialog->SetAutoClose(autoclose); + + dialog->Open(); + return dialog->GetSelectedItem(); +} + + +bool Interface_GUIDialogSelect::open_multi_select(KODI_HANDLE kodiBase, + const char* heading, + const char* entryIDs[], + const char* entryNames[], + bool entriesSelected[], + unsigned int size, + unsigned int autoclose) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogMultiSelect::{} - invalid data", __func__); + return false; + } + + CGUIDialogSelect* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( + WINDOW_DIALOG_SELECT); + if (!heading || !entryIDs || !entryNames || !entriesSelected || !dialog) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogMultiSelect::{} - invalid handler data (heading='{}', " + "entryIDs='{}', entryNames='{}', entriesSelected='{}', dialog='{}') on addon '{}'", + __func__, static_cast<const void*>(heading), static_cast<const void*>(entryIDs), + static_cast<const void*>(entryNames), static_cast<void*>(entriesSelected), + static_cast<void*>(dialog), addon->ID()); + return false; + } + + dialog->Reset(); + dialog->SetMultiSelection(true); + dialog->SetHeading(CVariant{heading}); + + std::vector<int> selectedIndexes; + + for (unsigned int i = 0; i < size; ++i) + { + dialog->Add(entryNames[i]); + if (entriesSelected[i]) + selectedIndexes.push_back(i); + } + + dialog->SetSelected(selectedIndexes); + if (autoclose > 0) + dialog->SetAutoClose(autoclose); + + dialog->Open(); + if (dialog->IsConfirmed()) + { + for (unsigned int i = 0; i < size; ++i) + entriesSelected[i] = false; + + selectedIndexes = dialog->GetSelectedItems(); + + for (unsigned int i = 0; i < selectedIndexes.size(); ++i) + { + if (selectedIndexes[i]) + entriesSelected[selectedIndexes[i]] = true; + } + } + + return true; +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/Select.h b/xbmc/addons/interfaces/gui/dialogs/Select.h new file mode 100644 index 0000000..5f2d0ef --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/Select.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/select.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Select.h" + */ + struct Interface_GUIDialogSelect + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static int open(KODI_HANDLE kodiBase, + const char* heading, + const char* entries[], + unsigned int size, + int selected, + unsigned int autoclose); + static bool open_multi_select(KODI_HANDLE kodiBase, + const char* heading, + const char* entryIDs[], + const char* entryNames[], + bool entriesSelected[], + unsigned int size, + unsigned int autoclose); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/TextViewer.cpp b/xbmc/addons/interfaces/gui/dialogs/TextViewer.cpp new file mode 100644 index 0000000..637975a --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/TextViewer.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "TextViewer.h" + +#include "ServiceBroker.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/TextViewer.h" +#include "dialogs/GUIDialogTextViewer.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "utils/log.h" + +namespace ADDON +{ + +void Interface_GUIDialogTextViewer::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogTextViewer = + new AddonToKodiFuncTable_kodi_gui_dialogTextViewer(); + + addonInterface->toKodi->kodi_gui->dialogTextViewer->open = open; +} + +void Interface_GUIDialogTextViewer::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogTextViewer; +} + +void Interface_GUIDialogTextViewer::open(KODI_HANDLE kodiBase, + const char* heading, + const char* text) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogTextViewer::{} - invalid data", __func__); + return; + } + + CGUIDialogTextViewer* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogTextViewer>( + WINDOW_DIALOG_TEXT_VIEWER); + if (!heading || !text || !dialog) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogTextViewer::{} - invalid handler data (heading='{}', text='{}', " + "dialog='{}') on addon '{}'", + __func__, static_cast<const void*>(heading), static_cast<const void*>(text), + static_cast<void*>(dialog), addon->ID()); + return; + } + + dialog->SetHeading(heading); + dialog->SetText(text); + dialog->Open(); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/TextViewer.h b/xbmc/addons/interfaces/gui/dialogs/TextViewer.h new file mode 100644 index 0000000..873dbbb --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/TextViewer.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/text_viewer.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/TextViewer.h" + */ + struct Interface_GUIDialogTextViewer + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static void open(KODI_HANDLE kodiBase, const char* heading, const char* text); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/gui/dialogs/YesNo.cpp b/xbmc/addons/interfaces/gui/dialogs/YesNo.cpp new file mode 100644 index 0000000..89dea58 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/YesNo.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "YesNo.h" + +#include "addons/binary-addons/AddonDll.h" +#include "addons/kodi-dev-kit/include/kodi/gui/dialogs/YesNo.h" +#include "dialogs/GUIDialogYesNo.h" +#include "messaging/helpers/DialogHelper.h" +#include "utils/log.h" + +using namespace KODI::MESSAGING; +using KODI::MESSAGING::HELPERS::DialogResponse; + +namespace ADDON +{ + +void Interface_GUIDialogYesNo::Init(AddonGlobalInterface* addonInterface) +{ + addonInterface->toKodi->kodi_gui->dialogYesNo = new AddonToKodiFuncTable_kodi_gui_dialogYesNo(); + + addonInterface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_single_text = + show_and_get_input_single_text; + addonInterface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_line_text = + show_and_get_input_line_text; + addonInterface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_line_button_text = + show_and_get_input_line_button_text; +} + +void Interface_GUIDialogYesNo::DeInit(AddonGlobalInterface* addonInterface) +{ + delete addonInterface->toKodi->kodi_gui->dialogYesNo; +} + +bool Interface_GUIDialogYesNo::show_and_get_input_single_text(KODI_HANDLE kodiBase, + const char* heading, + const char* text, + bool* canceled, + const char* noLabel, + const char* yesLabel) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogYesNo::{} - invalid data", __func__); + return false; + } + + if (!heading || !text || !canceled || !noLabel || !yesLabel) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogYesNo::{} - invalid handler data (heading='{}', text='{}', " + "canceled='{}', noLabel='{}', yesLabel='{}') on addon '{}'", + __func__, static_cast<const void*>(heading), static_cast<const void*>(text), + static_cast<void*>(canceled), static_cast<const void*>(noLabel), + static_cast<const void*>(yesLabel), addon->ID()); + return false; + } + + DialogResponse result = HELPERS::ShowYesNoDialogText(heading, text, noLabel, yesLabel); + *canceled = (result == DialogResponse::CHOICE_CANCELLED); + return (result == DialogResponse::CHOICE_YES); +} + +bool Interface_GUIDialogYesNo::show_and_get_input_line_text(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2, + const char* noLabel, + const char* yesLabel) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogYesNo::{} - invalid data", __func__); + return false; + } + + if (!heading || !line0 || !line1 || !line2 || !noLabel || !yesLabel) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogYesNo::{} - invalid handler data (heading='{}', line0='{}', " + "line1='{}', line2='{}', " + "noLabel='{}', yesLabel='{}') on addon '{}'", + __func__, static_cast<const void*>(heading), static_cast<const void*>(line0), + static_cast<const void*>(line1), static_cast<const void*>(line2), + static_cast<const void*>(noLabel), static_cast<const void*>(yesLabel), addon->ID()); + return false; + } + + return HELPERS::ShowYesNoDialogLines(heading, line0, line1, line2, noLabel, yesLabel) == + DialogResponse::CHOICE_YES; +} + +bool Interface_GUIDialogYesNo::show_and_get_input_line_button_text(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2, + bool* canceled, + const char* noLabel, + const char* yesLabel) +{ + CAddonDll* addon = static_cast<CAddonDll*>(kodiBase); + if (!addon) + { + CLog::Log(LOGERROR, "Interface_GUIDialogYesNo::{} - invalid data", __func__); + return false; + } + + if (!heading || !line0 || !line1 || !line2 || !canceled || !noLabel || !yesLabel) + { + CLog::Log(LOGERROR, + "Interface_GUIDialogYesNo::{} - invalid handler data (heading='{}', line0='{}', " + "line1='{}', line2='{}', " + "canceled='{}', noLabel='{}', yesLabel='{}') on addon '{}'", + __func__, static_cast<const void*>(heading), static_cast<const void*>(line0), + static_cast<const void*>(line1), static_cast<const void*>(line2), + static_cast<const void*>(canceled), static_cast<const void*>(noLabel), + static_cast<const void*>(yesLabel), addon->ID()); + return false; + } + + DialogResponse result = + HELPERS::ShowYesNoDialogLines(heading, line0, line1, line2, noLabel, yesLabel); + *canceled = (result == DialogResponse::CHOICE_CANCELLED); + return (result == DialogResponse::CHOICE_YES); +} + +} /* namespace ADDON */ diff --git a/xbmc/addons/interfaces/gui/dialogs/YesNo.h b/xbmc/addons/interfaces/gui/dialogs/YesNo.h new file mode 100644 index 0000000..84e5d73 --- /dev/null +++ b/xbmc/addons/interfaces/gui/dialogs/YesNo.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/yes_no.h" + +extern "C" +{ + + struct AddonGlobalInterface; + + namespace ADDON + { + + /*! + * @brief Global gui Add-on to Kodi callback functions + * + * To hold functions not related to a instance type and usable for + * every add-on type. + * + * Related add-on header is "./xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/YesNo.h" + */ + struct Interface_GUIDialogYesNo + { + static void Init(AddonGlobalInterface* addonInterface); + static void DeInit(AddonGlobalInterface* addonInterface); + + /*! + * @brief callback functions from add-on to kodi + * + * @note To add a new function use the "_" style to directly identify an + * add-on callback function. Everything with CamelCase is only to be used + * in Kodi. + * + * The parameter `kodiBase` is used to become the pointer for a `CAddonDll` + * class. + */ + //@{ + static bool show_and_get_input_single_text(KODI_HANDLE kodiBase, + const char* heading, + const char* text, + bool* canceled, + const char* noLabel, + const char* yesLabel); + + static bool show_and_get_input_line_text(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2, + const char* noLabel, + const char* yesLabel); + + static bool show_and_get_input_line_button_text(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2, + bool* canceled, + const char* noLabel, + const char* yesLabel); + //@} + }; + + } /* namespace ADDON */ +} /* extern "C" */ diff --git a/xbmc/addons/interfaces/platform/android/System.cpp b/xbmc/addons/interfaces/platform/android/System.cpp new file mode 100644 index 0000000..9f83b22 --- /dev/null +++ b/xbmc/addons/interfaces/platform/android/System.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "System.h" + +#include "CompileInfo.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/interfaces/AddonBase.h" +#include "addons/kodi-dev-kit/include/kodi/platform/android/System.h" + +#include "platform/android/activity/XBMCApp.h" + +static AddonToKodiFuncTable_android_system function_table; + +namespace ADDON +{ + +void Interface_Android::Register() +{ + function_table.get_jni_env = get_jni_env; + function_table.get_sdk_version = get_sdk_version; + function_table.get_class_name = get_class_name; + Interface_Base::RegisterInterface(Get); +} + +void* Interface_Android::Get(const std::string &name, const std::string &version) +{ + if (name == INTERFACE_ANDROID_SYSTEM_NAME + && version >= INTERFACE_ANDROID_SYSTEM_VERSION_MIN + && version <= INTERFACE_ANDROID_SYSTEM_VERSION) + return &function_table; + + return nullptr; +}; + +void* Interface_Android::get_jni_env() +{ + return xbmc_jnienv(); +} + +int Interface_Android::get_sdk_version() +{ + return CXBMCApp::Get().GetSDKVersion(); +} + +const char *Interface_Android::get_class_name() +{ + return CCompileInfo::GetClass(); +} + + +} //namespace ADDON diff --git a/xbmc/addons/interfaces/platform/android/System.h b/xbmc/addons/interfaces/platform/android/System.h new file mode 100644 index 0000000..59805ab --- /dev/null +++ b/xbmc/addons/interfaces/platform/android/System.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include <string> + +namespace ADDON +{ + +struct Interface_Android +{ + static void Register(); + static void* Get(const std::string &name, const std::string &version); + + static void* get_jni_env(); + static int get_sdk_version(); + static const char *get_class_name(); +}; + +} //namespace ADDON |