pkg_check_modules(pkgs REQUIRED
atspi-2
+ appcore-efl
capi-appfw-service-application
capi-appfw-application
capi-appfw-app-manager
SET(COMMON_FLAGS "-fdiagnostics-color=always -fPIC")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_FLAGS}")
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_FLAGS} -std=c++14 -g")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_FLAGS} -std=c++17 -g")
# install desktop file & icon
SET(RES_DIR "${CMAKE_INSTALL_PREFIX}/res")
BuildRequires: gettext-tools
BuildRequires: tts
BuildRequires: tts-devel
+BuildRequires: pkgconfig(appcore-efl)
+BuildRequires: pkgconfig(appcore-common)
BuildRequires: pkgconfig(capi-appfw-service-application)
BuildRequires: pkgconfig(capi-appfw-application)
BuildRequires: pkgconfig(capi-appfw-app-manager)
-FILE(GLOB SRCS *.cpp batch/*.cpp ./hiberlite/src/*.cpp)
+FILE(GLOB SRCS *.cpp batch/*.cpp ./hiberlite/src/*.cpp ./ui/*.cpp ./utils/*.cpp)
ADD_LIBRARY(universal-switch-obj OBJECT ${SRCS})
--- /dev/null
+#include "Layout.hpp"
+
+#include "../UniversalSwitchLog.hpp"
+
+#include <app.h>
+
+namespace ui
+{
+
+ void Layout::createEflObject()
+ {
+ uniqueObj_.reset(elm_layout_add(parent_->getObject()));
+ }
+
+ void Layout::createEflObject(const std::string &edjeFile, const std::string &group)
+ {
+ createEflObject();
+ setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+ std::string edjePath;
+ if (auto resPath = app_get_resource_path()) {
+ edjePath = std::string{resPath} + edjeFile;
+ free(resPath);
+ }
+ setFile(edjePath, group);
+ }
+
+ void Layout::setContent(const std::string &swallow, Widget *widget)
+ {
+ elm_layout_content_set(uniqueObj_.get(), swallow.c_str(), widget->getObject());
+ }
+
+ void Layout::setFile(const std::string &edjeFile, const std::string &group)
+ {
+ elm_layout_file_set(uniqueObj_.get(), edjeFile.c_str(), group.c_str());
+ }
+
+ void Layout::setTheme(const std::string &klass, const std::string &group, const std::string &style)
+ {
+ elm_layout_theme_set(uniqueObj_.get(), klass.c_str(), group.c_str(), style.c_str());
+ }
+
+ void Layout::setText(const std::string &part, const TranslatedString &text)
+ {
+ if (elm_layout_text_set(uniqueObj_.get(), part.c_str(), text.c_str()) == EINA_FALSE)
+ WARNING("Failed to set text: %s", text.c_str());
+ }
+
+}
--- /dev/null
+#ifndef LAYOUT_HPP
+#define LAYOUT_HPP
+
+#include "Widget.hpp"
+
+namespace ui
+{
+ class Layout : public Widget
+ {
+ template <typename T, typename... Args>
+ friend T *Widget::make(Widget *parent, Args &&... args);
+
+ public:
+ void setContent(const std::string &swallow, Widget *widget);
+ void setFile(const std::string &edjeFile, const std::string &group);
+ void setTheme(const std::string &klass, const std::string &group, const std::string &style);
+ void setText(const std::string &part, const TranslatedString &text);
+
+ protected:
+ using Widget::Widget;
+
+ private:
+ void createEflObject();
+ void createEflObject(const std::string &edjeFile, const std::string &group);
+ };
+
+}// namespace ui
+#endif
--- /dev/null
+#include "Popup.hpp"
+
+namespace ui
+{
+ void Popup::createEflObject()
+ {
+ uniqueObj_.reset(elm_popup_add(parent_->getObject()));
+ setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ show();
+ }
+
+ void Popup::createEflObject(const TranslatedString &title)
+ {
+ createEflObject();
+ setPartText("title,text", title);
+ }
+
+ void Popup::setOrientation(Elm_Popup_Orient orientation)
+ {
+ elm_popup_orient_set(uniqueObj_.get(), orientation);
+ }
+
+ void Popup::setAlignment(double h, double v)
+ {
+ elm_popup_align_set(uniqueObj_.get(), h, v);
+ }
+} //namesapce ui
--- /dev/null
+#ifndef POPUP_HPP
+#define POPUP_HPP
+
+#include "Widget.hpp"
+
+namespace ui
+{
+ class Popup : public Widget
+ {
+ template <typename T, typename... Args>
+ friend T *Widget::make(Widget *parent, Args &&... args);
+
+ public:
+ void setOrientation(Elm_Popup_Orient orientation);
+ void setAlignment(double h, double v);
+
+ protected:
+ using Widget::Widget;
+
+ private:
+ void createEflObject();
+ void createEflObject(const TranslatedString &title);
+ };
+} //namespace ui
+#endif
--- /dev/null
+#include "Widget.hpp"
+
+#include "../UniversalSwitchLog.hpp"
+
+namespace ui
+{
+
+ Widget::Widget(Widget *parent)
+ : parent_(parent)
+ {}
+
+ Widget::~Widget()
+ {
+ for (auto &it : smartCallbacks_) {
+ evas_object_smart_callback_del(getObject(), it.first.c_str(), smartCallbackMethod);
+ }
+ }
+
+ void Widget::setText(const TranslatedString &text)
+ {
+ elm_object_text_set(uniqueObj_.get(), text.c_str());
+ }
+
+ void Widget::setPartText(const std::string &partName, const TranslatedString &text)
+ {
+ elm_object_part_text_set(uniqueObj_.get(), partName.c_str(), text.c_str());
+ }
+
+ void Widget::setWeightHint(double x, double y)
+ {
+ evas_object_size_hint_weight_set(uniqueObj_.get(), x, y);
+ }
+
+ void Widget::setAlignHint(double x, double y)
+ {
+ evas_object_size_hint_align_set(uniqueObj_.get(), x, y);
+ }
+
+ void Widget::setMinSizeHint(Evas_Coord v, Evas_Coord h)
+ {
+ evas_object_size_hint_min_set(uniqueObj_.get(), v, h);
+ }
+
+ void Widget::setMaxSizeHint(Evas_Coord v, Evas_Coord h)
+ {
+ evas_object_size_hint_max_set(uniqueObj_.get(), v, h);
+ }
+
+ void Widget::setAspectHint(Evas_Aspect_Control aspect, Evas_Coord w, Evas_Coord h)
+ {
+ evas_object_size_hint_aspect_set(uniqueObj_.get(), aspect, w, h);
+ }
+
+ Rectangle Widget::getGeometry()
+ {
+ int x, y, w, h;
+ evas_object_geometry_get(uniqueObj_.get(), &x, &y, &w, &h);
+ return {{x, y}, {w, h}};
+ }
+
+ void Widget::setPosition(Point anchor)
+ {
+ evas_object_move(uniqueObj_.get(), anchor.x, anchor.y);
+ }
+
+ void Widget::setEvasSmartCallback(const std::string &eventName, std::function<void()> callback)
+ {
+ auto cbData = std::make_unique<WidgetCallback::Data<Widget, std::string>>(this, eventName);
+ auto dataPtr = cbData.get();
+ smartCallbacks_.insert_or_assign(eventName, WidgetCallback::Value<Widget, std::string>{std::move(callback), std::move(cbData)});
+ evas_object_smart_callback_add(getObject(), eventName.c_str(), smartCallbackMethod, dataPtr);
+ }
+
+ void Widget::removeEvasSmartCallback(const std::string &eventName)
+ {
+ evas_object_smart_callback_del(uniqueObj_.get(), eventName.c_str(), smartCallbackMethod);
+ smartCallbacks_.erase(eventName);
+ }
+
+ void Widget::setEextEventCallback(const Eext_Callback_Type type, std::function<void()> callback)
+ {
+ auto cbData = std::make_unique<WidgetCallback::Data<Widget, Eext_Callback_Type>>(this, type);
+ auto dataPtr = cbData.get();
+ eextEventCallbacks_.insert_or_assign(
+ type, WidgetCallback::Value<Widget, Eext_Callback_Type>{std::move(callback), std::move(cbData)});
+ eext_object_event_callback_add(getObject(), type, eextEventMethod, dataPtr);
+ }
+
+ void Widget::setStyle(const std::string &style)
+ {
+ elm_object_style_set(uniqueObj_.get(), style.c_str());
+ }
+
+ void Widget::setColor(int r, int g, int b, int a)
+ {
+ evas_object_color_set(uniqueObj_.get(), r, g, b, a);
+ }
+
+ void Widget::setContent(Widget *widget)
+ {
+ elm_object_content_set(uniqueObj_.get(), widget->getObject());
+ }
+
+ void Widget::setPartContent(const std::string &part, Widget *content)
+ {
+ elm_object_part_content_set(uniqueObj_.get(), part.c_str(), content->getObject());
+ }
+
+ void Widget::setHomogeneousDimensions()
+ {
+ elm_box_homogeneous_set(uniqueObj_.get(), EINA_TRUE);
+ }
+
+ void Widget::setPropagateEvents(bool prop)
+ {
+ evas_object_propagate_events_set(uniqueObj_.get(), prop ? EINA_TRUE : EINA_FALSE);
+ }
+
+ void Widget::disable(bool disable)
+ {
+ disable ? elm_object_disabled_set(uniqueObj_.get(), EINA_TRUE) : elm_object_disabled_set(uniqueObj_.get(), EINA_FALSE);
+ }
+
+ void Widget::emitSignal(const std::string &signal)
+ {
+ elm_object_signal_emit(uniqueObj_.get(), signal.c_str(), "");
+ }
+
+ void Widget::setFocus(bool focus)
+ {
+ elm_object_focus_set(uniqueObj_.get(), focus ? EINA_TRUE : EINA_FALSE);
+ }
+
+ void Widget::show()
+ {
+ evas_object_show(uniqueObj_.get());
+ }
+
+ void Widget::hide()
+ {
+ evas_object_hide(uniqueObj_.get());
+ }
+
+ void Widget::setPassEvents(bool pass)
+ {
+ evas_object_pass_events_set(uniqueObj_.get(), pass ? EINA_TRUE : EINA_FALSE);
+ }
+
+ Evas_Object *Widget::getObject()
+ {
+ return uniqueObj_.get();
+ }
+
+ Widget *Widget::getParent()
+ {
+ return parent_;
+ }
+
+ void Widget::addChild(std::unique_ptr<Widget> child)
+ {
+ child->parent_ = this;
+ children_.push_back(std::move(child));
+ }
+
+ void Widget::removeChild(Widget *child)
+ {
+ if (!child)
+ return;
+
+ for (auto it = children_.begin(); it != children_.end(); ++it) {
+ if (it->get() == child) {
+ children_.erase(it);
+ break;
+ }
+ }
+ }
+
+ void Widget::smartCallbackMethod(void *data, Evas_Object *obj, void *event_info)
+ {
+ auto cbData = static_cast<WidgetCallback::Data<Widget, std::string> *>(data);
+
+ auto cb = cbData->self->smartCallbacks_.find(cbData->eventName);
+ if (cb == cbData->self->smartCallbacks_.end()) {
+ ERROR("No callback registered for this event");
+ return;
+ }
+ auto c = cb->second.callback;
+ c();
+ }
+
+ void Widget::eextEventMethod(void *data, Evas_Object *obj, void *event_info)
+ {
+ auto cbData = static_cast<WidgetCallback::Data<Widget, Eext_Callback_Type> *>(data);
+
+ auto cb = cbData->self->eextEventCallbacks_.find(cbData->eventName);
+ if (cb == cbData->self->eextEventCallbacks_.end()) {
+ ERROR("No callback registered for this event");
+ return;
+ }
+ auto c = cb->second.callback;
+ c();
+ }
+
+} //namesapce ui
\ No newline at end of file
--- /dev/null
+#ifndef WIDGET_HPP
+#define WIDGET_HPP
+
+#include "../Geometry.hpp"
+#include "../utils/TranslatedString.hpp"
+#include "../utils/WidgetCallback.hpp"
+#include "../utils/utils.hpp"
+
+#include <Elementary.h>
+#include <efl_extension.h>
+#include <functional>
+#include <memory>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+namespace ui
+{
+ class Widget
+ {
+ public:
+ Widget(const Widget &) = delete;
+ Widget(Widget &&) = delete;
+ virtual ~Widget();
+
+ template <typename T, typename... Args>
+ static T *make(Widget *parent, Args &&... args)
+ {
+ auto raw = new T(parent);
+ parent->addChild(std::unique_ptr<T>(raw));
+ raw->createEflObject(std::forward<Args>(args)...);
+ return raw;
+ }
+
+ void setText(const TranslatedString &text);
+ void setPartText(const std::string &partName, const TranslatedString &text);
+ void setWeightHint(double x, double y);
+ void setAlignHint(double x, double y);
+ void setMinSizeHint(Evas_Coord v, Evas_Coord h);
+ void setMaxSizeHint(Evas_Coord v, Evas_Coord h);
+ void setAspectHint(Evas_Aspect_Control aspect, Evas_Coord w, Evas_Coord h);
+ Rectangle getGeometry();
+ void setPosition(Point anchor);
+ void setEvasSmartCallback(const std::string &eventName, std::function<void()> callback);
+ void removeEvasSmartCallback(const std::string &eventName);
+ void setEextEventCallback(const Eext_Callback_Type type, std::function<void()> callback);
+ void setStyle(const std::string &style);
+ void setColor(int r, int g, int b, int a);
+ void setContent(Widget *widget);
+ void setPartContent(const std::string &part, Widget *content);
+ void setHomogeneousDimensions();
+ void setPropagateEvents(bool prop);
+ void setFocus(bool focus);
+ void disable(bool disable);
+ void emitSignal(const std::string &signal);
+ void show();
+ void hide();
+ void setPassEvents(bool pass);
+
+ Evas_Object *getObject();
+ Widget *getParent();
+ void addChild(std::unique_ptr<Widget> child);
+ void removeChild(Widget *child);
+
+ protected:
+ Widget() = default;
+ Widget(Widget *parent);
+ static void smartCallbackMethod(void *data, Evas_Object *obj, void *event_info);
+ static void eextEventMethod(void *data, Evas_Object *obj, void *event_info);
+
+ std::unique_ptr<Evas_Object, utils::EvasDeleter> uniqueObj_;
+ Widget *parent_ = nullptr;
+ std::vector<std::unique_ptr<Widget>> children_;
+ std::unordered_map<std::string, WidgetCallback::Value<Widget, std::string>> smartCallbacks_;
+ std::unordered_map<Eext_Callback_Type, WidgetCallback::Value<Widget, Eext_Callback_Type>> eextEventCallbacks_;
+ };
+
+} //namespace ui
+
+#endif
--- /dev/null
+#include "Window.hpp"
+
+namespace ui
+{
+
+ Window::Window(const std::string &title)
+ {
+ uniqueObj_.reset(elm_win_add(NULL, NULL, ELM_WIN_BASIC));
+
+ elm_win_title_set(uniqueObj_.get(), title.c_str());
+
+ elm_win_indicator_mode_set(uniqueObj_.get(), ELM_WIN_INDICATOR_SHOW);
+ elm_win_indicator_opacity_set(uniqueObj_.get(), ELM_WIN_INDICATOR_OPAQUE);
+ }
+
+ void Window::setConformant(bool conformant)
+ {
+ elm_win_conformant_set(uniqueObj_.get(), conformant ? EINA_TRUE : EINA_FALSE);
+ }
+
+ void Window::addResizeObject(Widget *widget)
+ {
+ elm_win_resize_object_add(uniqueObj_.get(), widget->getObject());
+ }
+
+ void Window::addAvailableRotations(std::vector<int> rotations)
+ {
+ elm_win_wm_rotation_available_rotations_set(uniqueObj_.get(), rotations.data(), rotations.size());
+ }
+
+} //namespace ui
\ No newline at end of file
--- /dev/null
+#ifndef WINDOW_HPP
+#define WINDOW_HPP
+
+#include "Widget.hpp"
+
+namespace ui
+{
+ class Window : public Widget
+ {
+ public:
+ Window(const std::string &title);
+
+ void setConformant(bool conformant);
+ void addResizeObject(Widget *widget);
+ void addAvailableRotations(std::vector<int> rotations);
+ };
+} // namespace ui
+#endif
--- /dev/null
+#ifndef OBSERVABLE_HPP
+#define OBSERVABLE_HPP
+
+#include <functional>
+#include <vector>
+
+template <typename... ARGS>
+class Observable
+{
+ public:
+ virtual ~Observable() = default;
+
+ void attach(std::function<void(ARGS...)> onChange)
+ {
+ onChangeCallbacks_.push_back(std::move(onChange));
+ }
+
+ protected:
+ void notify(ARGS... args)
+ {
+ for (auto &c : this->onChangeCallbacks_)
+ if (c)
+ c(args...);
+ }
+
+ std::vector<std::function<void(ARGS...)>> onChangeCallbacks_;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TranslatedString.hpp"
+
+#include <appcore-common.h>
+#include <cstring>
+
+TranslatedString::TranslatedString(const std::string &str)
+ : value(std::string{gettext(str.c_str())})
+{}
+
+TranslatedString::TranslatedString(const char *str)
+ : value(std::string{gettext(str), strlen(gettext(str))})
+{}
+
+TranslatedString &TranslatedString::operator+=(const TranslatedString &ts)
+{
+ value += ts.value;
+ return *this;
+}
+
+bool TranslatedString::empty() const
+{
+ return value.empty();
+}
+
+std::string TranslatedString::str() const
+{
+ return value;
+}
+
+const char *TranslatedString::c_str() const
+{
+ return value.c_str();
+}
+
+TranslatedString operator+(TranslatedString lString, const TranslatedString &rString)
+{
+ lString += rString;
+ return lString;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TRANSLATED_STRING_HPP
+#define TRANSLATED_STRING_HPP
+
+#include "../UniversalSwitchLog.hpp"
+
+#include <string>
+/**
+ * Class containing strings translated with usage of internatonalization API
+ *
+ * Main purpose of this class is to distinguish objects containing raw i18n keys
+ * from already translated
+ */
+class TranslatedString
+{
+ public:
+ TranslatedString() = default;
+ TranslatedString(const std::string &str);
+ TranslatedString(const char *str);
+
+ TranslatedString &operator+=(const TranslatedString &ts);
+
+ template <typename... ARGS>
+ static TranslatedString create(const char *str, const ARGS &... args)
+ {
+ char buf[1024] = {0};
+ auto ret = snprintf(buf, sizeof(buf), gettext(str), args...);
+ if (ret > 1024) {
+ ERROR("snprintf failed");
+ return {};
+ }
+ return {buf};
+ }
+
+ bool empty() const;
+
+ std::string str() const;
+ const char *c_str() const;
+
+ private:
+ std::string value;
+};
+
+TranslatedString operator+(TranslatedString lString, const TranslatedString &rString);
+
+#endif
--- /dev/null
+#ifndef WIDGET_CALLBACK_HPP
+#define WIDGET_CALLBACK_HPP
+
+#include <functional>
+#include <memory>
+#include <unordered_map>
+
+class Widget;
+
+namespace WidgetCallback
+{
+ template <typename S, typename T>
+ struct Data
+ {
+ Data(S *self, const T &name)
+ : self(self), eventName(name)
+ {}
+
+ S *self = nullptr;
+ T eventName{};
+ };
+
+ template <typename S, typename T>
+ struct Value
+ {
+ std::function<void()> callback;
+ std::unique_ptr<Data<S, T>> data;
+ };
+
+} // namespace WidgetCallback
+#endif
--- /dev/null
+/*
+ * Copyright 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILS_HPP
+#define UTILS_HPP
+
+#include "Elementary.h"
+
+#include <sstream>
+#include <vector>
+
+using SettingCallback = void (*)(void *, Evas_Object *, void *);
+
+namespace utils
+{
+ struct EvasDeleter
+ {
+ template <typename T>
+ void operator()(T *t) const
+ {
+ if (t)
+ evas_object_del(t);
+ }
+ };
+
+ struct ElmGenlistItemClassDeleter
+ {
+ void operator()(Elm_Genlist_Item_Class *it) const
+ {
+ if (it)
+ elm_genlist_item_class_free(it);
+ }
+ };
+
+ template <typename T>
+ struct Range
+ {
+ T begin{};
+ T end{};
+ };
+
+ template <typename In, typename Out = double>
+ Out rescale(In value, Range<In> source, Range<Out> target = {0.0, 1.0})
+ {
+ auto denominator = source.end - source.begin;
+ auto rescaledValue = target.begin;
+ if (denominator != 0)
+ rescaledValue += (value - source.begin) * (target.end - target.begin) / denominator;
+
+ return rescaledValue;
+ }
+
+ inline std::string doubleToPercent(double val)
+ {
+ return std::to_string(static_cast<int>(val * 100)) + "%";
+ }
+
+ inline std::string doubleToString(double val, size_t precision)
+ {
+ std::ostringstream out;
+ out.precision(1);
+
+ out << std::fixed << val;
+
+ return out.str();
+ }
+
+ inline std::vector<std::string> stringSplitByDelimiter(const std::string &s, char delimiter)
+ {
+ std::vector<std::string> tokens;
+ std::string token;
+ std::istringstream tokenStream(s);
+ while (std::getline(tokenStream, token, delimiter)) {
+ tokens.push_back(token);
+ }
+ return tokens;
+ }
+} // namespace utils
+
+#endif