diff --git a/CMakeLists.txt b/CMakeLists.txt
index 92c096b..9e28600 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,7 +46,7 @@ if (APPLE)
models/apple/SGCalendarManager.h
models/apple/SGCalendarExporter.h
models/apple/SGCalendarExporter.mm
- )
+ models/color.mm)
endif ()
set(MODELS ${MODELS_PLATFORM_FILES}
@@ -96,7 +96,9 @@ set(MODELS ${MODELS_PLATFORM_FILES}
models/event.cpp
models/event.h
models/color.cpp
- models/color.h)
+ models/color.h
+ models/theme.cpp
+ models/theme.h)
set(MODELS_TESTS
models/tests/activity_tests.cpp
diff --git a/deployment/Info.plist b/deployment/Info.plist
index 5f614e0..7bf71da 100644
--- a/deployment/Info.plist
+++ b/deployment/Info.plist
@@ -53,7 +53,5 @@
Strategr would be able to export activity sessions as events to the Calendar
SUFeedURL
${APPCAST_URL}
- SUPublicEDKey
- G0A4GIM5nGFE2ANNKzogtjCjWHwItD6oy56yL1qJngQ=
diff --git a/models/activity.cpp b/models/activity.cpp
index 61f8d0b..c4b4f3a 100644
--- a/models/activity.cpp
+++ b/models/activity.cpp
@@ -4,90 +4,92 @@
#include "activity.h"
#include "activityinvalidpropertyexception.h"
-const std::vector &stg::activity::default_colors() {
- const static std::vector colors = {
- {"#FF6562", "Red"},
- {"#FFB700", "Orange"},
- {"#FFD600", "Yellow"},
- {"#A463F2", "Purple"},
- {"#D5008F", "Indigo"},
- {"#19A974", "Green"},
- {"#357EDD", "Blue"},
- {"#000000", "Black"},
- {"#777777", "Gray"}
+namespace stg {
+ auto activity::default_colors() -> const std::vector & {
+ const static std::vector colors = {
+ {"#FF6562", "Red"},
+ {"#FFB700", "Orange"},
+ {"#FFD600", "Yellow"},
+ {"#A463F2", "Purple"},
+ {"#D5008F", "Indigo"},
+ {"#19A974", "Green"},
+ {"#357EDD", "Blue"},
+ {"#000000", "Black"},
+ {"#777777", "Gray"}
+ };
+
+ return colors;
};
- return colors;
-};
+ activity::activity(name_t name, color_t color) : _color(std::move(color)) {
+ if (!is_valid(name)) {
+ throw empty_name_exception();
+ }
-stg::activity::activity(name_t name, color_t color) : _color(std::move(color)) {
- if (!is_valid(name)) {
- throw empty_name_exception();
+ _name = std::move(name);
}
- _name = std::move(name);
-}
-
-bool stg::activity::is_valid(const activity::name_t &name) {
- bool white_spaces_only = name.find_first_not_of(" \t\n\v\f\r") == std::string::npos;
- return !white_spaces_only;
-}
-
-stg::activity::invalid_property_exception stg::activity::empty_name_exception() {
- const auto message = "activity name can't be empty";
- return invalid_property_exception(message);
-}
-
-const stg::activity::name_t &stg::activity::name() const {
- return _name;
-}
-
-const stg::activity::color_t &stg::activity::color() const {
- return _color;
-}
-
-bool stg::operator==(const stg::activity &lhs, const stg::activity &rhs) {
- return lhs.name() == rhs.name() &&
- lhs.color() == rhs.color();
-}
-
-bool stg::operator!=(const stg::activity &lhs, const stg::activity &rhs) {
- return !(lhs == rhs);
-}
-
-std::ostream &stg::operator<<(std::ostream &os,
- const stg::activity &activity) {
- os << "activity("
- << activity.name()
- << ", "
- << activity.color()
- << ")";
-
- return os;
-}
-
-stg::activity stg::activity::copy_changing_name(const name_t &name) const {
- return activity(name, _color);
-}
-
-stg::activity stg::activity::copy_changing_color(const color_t &color) const {
- return activity(_name, color);
-}
-
-nlohmann::json stg::activity::to_json() {
- nlohmann::json j;
- j[keys::name] = this->name();
- j[keys::color] = this->color();
- return j;
-}
-
-stg::activity stg::activity::from_json(const nlohmann::json &j) {
- auto name = j[keys::name];
-
- stg::color color = activity::default_color;
- if (j.count(keys::color) && !j[keys::color].is_null()) {
- color = j[keys::color];
+ auto activity::is_valid(const activity::name_t &name) -> bool {
+ bool white_spaces_only = name.find_first_not_of(" \t\n\v\f\r") == std::string::npos;
+ return !white_spaces_only;
}
- return activity{name, color};
+ auto activity::empty_name_exception() -> activity::invalid_property_exception {
+ const auto *message = "activity name can't be empty";
+ return invalid_property_exception(message);
+ }
+
+ auto activity::name() const -> const activity::name_t & {
+ return _name;
+ }
+
+ auto activity::color() const -> const activity::color_t & {
+ return _color;
+ }
+
+ auto operator==(const stg::activity &lhs, const stg::activity &rhs) -> bool {
+ return lhs.name() == rhs.name() &&
+ lhs.color() == rhs.color();
+ }
+
+ auto operator!=(const stg::activity &lhs, const stg::activity &rhs) -> bool {
+ return !(lhs == rhs);
+ }
+
+ auto operator<<(std::ostream &os,
+ const stg::activity &activity) -> std::ostream & {
+ os << "activity("
+ << activity.name()
+ << ", "
+ << activity.color()
+ << ")";
+
+ return os;
+ }
+
+ auto activity::with_name(const name_t &name) const -> activity {
+ return activity(name, _color);
+ }
+
+ auto activity::with_color(const color_t &color) const -> activity {
+ return activity(_name, color);
+ }
+
+ auto activity::to_json() const -> nlohmann::json {
+ nlohmann::json j;
+ j[keys::name] = this->name();
+ j[keys::color] = this->color();
+ return j;
+ }
+
+ auto activity::from_json(const nlohmann::json &j) -> activity {
+ auto name = j[keys::name];
+
+ stg::color color = activity::default_color;
+ if (j.count(keys::color) && !j[keys::color].is_null()) {
+ color = j[keys::color];
+ }
+
+ return activity{name, color};
+ }
}
\ No newline at end of file
diff --git a/models/activity.h b/models/activity.h
index 3527968..7ff5c1c 100644
--- a/models/activity.h
+++ b/models/activity.h
@@ -17,24 +17,49 @@ namespace stg {
class invalid_property_exception;
static constexpr auto default_color = "#000000";
- static const std::vector &default_colors();
+ static auto default_colors() -> const std::vector &;
explicit activity(name_t name, color_t color = default_color) noexcept(false);
- const name_t &name() const;
- const color_t &color() const;
+ auto name() const -> const name_t &;
+ auto color() const -> const color_t &;
- activity copy_changing_name(const name_t &name) const;
- activity copy_changing_color(const color_t &color) const;
+ auto light_color() const -> color_t {
+ auto clr = color();
+ clr.set_alpha_component(0.15);
- friend bool operator==(const activity &lhs, const activity &rhs);
- friend bool operator!=(const activity &lhs, const activity &rhs);
+ return clr;
+ }
- friend std::ostream &operator<<(std::ostream &os,
- const activity &activity);
+ auto desaturated_light_color() const -> color_t {
+ auto clr = color();
+ clr.set_hsl(clr.hue(), 0.3, 0.75);
+ clr.set_alpha_component(0.2);
- nlohmann::json to_json();
- static activity from_json(const nlohmann::json &j);
+ return clr;
+ }
+
+ auto desaturated_dark_color() const -> color_t {
+ auto clr = color_t();
+
+ if (color().lightness() < 0.2)
+ clr = color_t(0xffffffff);
+
+ clr.set_alpha_component(0.1);
+ return clr;
+ }
+
+ auto with_name(const name_t &name) const -> activity;
+ auto with_color(const color_t &color) const -> activity;
+
+ friend auto operator==(const activity &lhs, const activity &rhs) -> bool;
+ friend auto operator!=(const activity &lhs, const activity &rhs) -> bool;
+
+ friend auto operator<<(std::ostream &os,
+ const activity &activity) -> std::ostream &;
+
+ auto to_json() const -> nlohmann::json;
+ static auto from_json(const nlohmann::json &j) -> activity;
private:
name_t _name;
@@ -45,9 +70,9 @@ namespace stg {
static constexpr auto color = "color";
};
- static invalid_property_exception empty_name_exception();
+ static auto empty_name_exception() -> invalid_property_exception;
- static bool is_valid(const name_t &name);
+ static auto is_valid(const name_t &name) -> bool;
};
}
diff --git a/models/activityinvalidpropertyexception.cpp b/models/activityinvalidpropertyexception.cpp
index b86743f..53a3bbb 100644
--- a/models/activityinvalidpropertyexception.cpp
+++ b/models/activityinvalidpropertyexception.cpp
@@ -5,10 +5,12 @@
#include "activityinvalidpropertyexception.h"
#include
-const char *stg::activity::invalid_property_exception::what() const noexcept {
- return message.c_str();
-}
+namespace stg {
+ activity::invalid_property_exception::invalid_property_exception(std::string message) :
+ std::exception(),
+ message(std::move(message)) {}
-stg::activity::invalid_property_exception::invalid_property_exception(std::string message) :
- std::exception(),
- message(std::move(message)) {}
+ auto activity::invalid_property_exception::what() const noexcept -> const char * {
+ return message.c_str();
+ }
+}
\ No newline at end of file
diff --git a/models/activityinvalidpropertyexception.h b/models/activityinvalidpropertyexception.h
index 9f80c34..fcdd0f0 100644
--- a/models/activityinvalidpropertyexception.h
+++ b/models/activityinvalidpropertyexception.h
@@ -11,7 +11,7 @@ namespace stg {
class activity::invalid_property_exception : public std::exception {
public:
explicit invalid_property_exception(std::string message);
- const char *what() const noexcept override;
+ auto what() const noexcept -> const char * override;
private:
std::string message;
diff --git a/models/activitylist.cpp b/models/activitylist.cpp
index 4887a1a..e50804c 100644
--- a/models/activitylist.cpp
+++ b/models/activitylist.cpp
@@ -8,218 +8,219 @@
#include "activitylist.h"
#include "utility.h"
-void stg::activity_list::silently_add(const activity &activity) {
- if (has(activity)) {
- throw already_present_exception();
- }
+namespace stg {
+ void activity_list::silently_add(const activity &activity) {
+ if (has(activity)) {
+ throw already_present_exception();
+ }
- _data.push_back(std::make_shared(activity));
+ _data.push_back(std::make_shared(activity));
- if (!search_query.empty())
- search(search_query);
-}
+ if (!search_query.empty())
+ search(search_query);
+ }
-void stg::activity_list::add(const activity &activity) {
- silently_add(activity);
+ void activity_list::add(const activity &activity) {
+ silently_add(activity);
- on_change_event();
-}
+ on_change_event();
+ }
-void stg::activity_list::silently_remove_at_index(stg::activity_index index) {
- _data.erase(_data.begin() + index);
+ void activity_list::silently_remove_at_index(activity_index_t index) {
+ _data.erase(_data.begin() + index);
- if (!search_query.empty())
- search(search_query);
-}
+ if (!search_query.empty())
+ search(search_query);
+ }
-void stg::activity_list::remove_at_index(activity_index index) {
- silently_remove_at_index(index);
- on_change_event();
-}
+ void activity_list::remove_at_index(activity_index_t index) {
+ silently_remove_at_index(index);
-void stg::activity_list::silently_edit_at_index(activity_index index, const activity &new_activity) {
- if (*_data[index] == new_activity) {
- return;
+ on_change_event();
}
- if (has(new_activity)) {
- throw already_present_exception();
- }
+ void activity_list::silently_edit_at_index(activity_index_t index, const activity &new_activity) {
+ if (*_data[index] == new_activity) {
+ return;
+ }
- _data[index] = std::make_shared(new_activity);
+ if (has(new_activity)) {
+ throw already_present_exception();
+ }
- if (!search_query.empty()) {
- search(search_query);
- }
-}
+ _data[index] = std::make_shared(new_activity);
-void stg::activity_list::edit_at_index(activity_index index, const activity &new_activity) {
- if (*_data[index] == new_activity) {
- return;
+ if (!search_query.empty()) {
+ search(search_query);
+ }
}
- silently_edit_at_index(index, new_activity);
+ void activity_list::edit_at_index(activity_index_t index, const activity &new_activity) {
+ if (*_data[index] == new_activity) {
+ return;
+ }
+
+ silently_edit_at_index(index, new_activity);
- on_change_event();
-}
+ on_change_event();
+ }
-bool stg::activity_list::has(const activity &searched_activity) const {
- for (const auto &activity : _data) {
- if (*activity == searched_activity) {
- return true;
+ auto activity_list::has(const activity &searched_activity) const -> bool {
+ for (const auto &activity : _data) {
+ if (*activity == searched_activity) {
+ return true;
+ }
}
+
+ return false;
}
- return false;
-}
+ void activity_list::silently_drag(activity_index_t from_index, activity_index_t to_index) {
+ if (from_index == to_index) {
+ return;
+ }
-void stg::activity_list::silently_drag(activity_index from_index, activity_index to_index) {
- if (from_index == to_index) {
- return;
+ if (from_index > to_index)
+ std::rotate(_data.rend() - from_index - 1,
+ _data.rend() - from_index,
+ _data.rend() - to_index);
+ else
+ std::rotate(_data.begin() + from_index,
+ _data.begin() + from_index + 1,
+ _data.begin() + to_index + 1);
}
- if (from_index > to_index)
- std::rotate(_data.rend() - from_index - 1,
- _data.rend() - from_index,
- _data.rend() - to_index);
- else
- std::rotate(_data.begin() + from_index,
- _data.begin() + from_index + 1,
- _data.begin() + to_index + 1);
-}
+ void activity_list::drag(activity_index_t from_index, activity_index_t to_index) {
+ silently_drag(from_index, to_index);
-void stg::activity_list::drag(activity_index from_index, activity_index to_index) {
- silently_drag(from_index, to_index);
+ on_change_event();
+ }
- on_change_event();
-}
+ auto activity_list::class_print_name() const -> std::string {
+ return "activity_list";
+ }
-std::string stg::activity_list::class_print_name() const {
- return "activity_list";
-}
+ activity_list::activity_list(const std::vector &from_vector) {
+ std::transform(from_vector.begin(),
+ from_vector.end(),
+ std::back_inserter(_data),
+ [](auto &activity) {
+ return std::make_shared(activity);
+ });
-stg::activity_list::activity_list(const std::vector &from_vector) {
- std::transform(from_vector.begin(),
- from_vector.end(),
- std::back_inserter(_data),
- [](auto &activity) {
- return std::make_shared(activity);
- });
+ if (!search_query.empty())
+ search(search_query);
+ }
- if (!search_query.empty())
- search(search_query);
-}
+ activity_list::activity_list(const std::vector> &from_vector) {
+ std::transform(from_vector.begin(),
+ from_vector.end(),
+ std::back_inserter(_data),
+ [](auto &activity) {
+ return activity;
+ });
-stg::activity_list::activity_list(const std::vector> &from_vector) {
- std::transform(from_vector.begin(),
- from_vector.end(),
- std::back_inserter(_data),
- [](auto &activity) {
- return activity;
- });
+ if (!search_query.empty())
+ search(search_query);
+ }
- if (!search_query.empty())
- search(search_query);
-}
+ auto activity_list::operator[](activity_index_t item_index) const -> const activity & {
+ return *_data[item_index];
+ }
-const stg::activity &stg::activity_list::operator[](activity_index item_index) const {
- return *_data[item_index];
-}
+ auto activity_list::at(activity_index_t item_index) const -> stg::activity * {
+ return _data.at(item_index).get();
+ }
-stg::activity *stg::activity_list::at(activity_index item_index) const {
- return _data.at(item_index).get();
-}
+ auto activity_list::index_of(const activity *activity) const -> std::optional {
+ auto it = std::find_if(_data.begin(), _data.end(), [=](auto &a) {
+ return a.get() == activity;
+ });
-std::optional
-stg::activity_list::index_of(const activity *activity) const {
- auto it = std::find_if(_data.begin(), _data.end(), [=](auto &a) {
- return a.get() == activity;
- });
+ if (it == _data.end()) {
+ return std::nullopt;
+ }
- if (it == _data.end()) {
- return std::nullopt;
+ return std::distance(_data.begin(), it);
}
- return std::distance(_data.begin(), it);
-}
+ auto activity_list::index_of(const activity &activity) const -> std::optional {
+ auto it = std::find_if(_data.begin(),
+ _data.end(),
+ [&](auto &a) {
+ return *a == activity;
+ });
-std::optional
-stg::activity_list::index_of(const activity &activity) const {
- auto it = std::find_if(_data.begin(), _data.end(), [&](auto &a) {
- return *a == activity;
- });
+ if (it == _data.end()) {
+ return std::nullopt;
+ }
- if (it == _data.end()) {
- return std::nullopt;
+ return std::distance(_data.begin(), it);
}
- return std::distance(_data.begin(), it);
-}
-
-bool stg::activity_list::search(std::string query) const {
- text::strip_bounding_whitespaces(query);
+ auto activity_list::search(std::string query) const -> bool {
+ text::strip_bounding_whitespaces(query);
- search_query = query;
+ search_query = query;
- if (query.empty()) {
- auto was_updated = !search_results.empty();
- search_results.clear();
+ if (query.empty()) {
+ auto was_updated = !search_results.empty();
+ search_results.clear();
- return was_updated;
- }
+ return was_updated;
+ }
- query = text::utf8_fold_case(query);
+ query = text::utf8_fold_case(query);
- activity_list::data_t results;
- std::copy_if(begin(),
- end(),
- std::back_inserter(results),
- [&query](auto activity) {
- auto name = text::utf8_fold_case(activity->name());
- return name.find(query) != std::string::npos;
- });
+ data_t results;
+ std::copy_if(begin(),
+ end(),
+ std::back_inserter(results),
+ [&query](auto activity) {
+ auto name = text::utf8_fold_case(activity->name());
+ return name.find(query) != std::string::npos;
+ });
- auto was_updated = search_results != results;
+ auto was_updated = search_results != results;
- search_results = results;
+ search_results = results;
- return was_updated;
-}
+ return was_updated;
+ }
-const stg::activity_list::data_t &stg::activity_list::filtered() const {
- if (search_query.empty())
- return _data;
+ auto activity_list::filtered() const -> const stg::activity_list::data_t & {
+ if (search_query.empty())
+ return _data;
- return search_results;
-}
+ return search_results;
+ }
-std::optional
-stg::activity_list::index_from_filtered(index_t index_in_filtered) const {
- auto *activity = filtered().at(index_in_filtered).get();
- return index_of(activity);
-}
+ auto activity_list::index_from_filtered(index_t index_in_filtered) const -> std::optional {
+ auto *activity = filtered().at(index_in_filtered).get();
+ return index_of(activity);
+ }
-std::optional
-stg::activity_list::index_in_filtered(index_t activity_index) const {
- auto activity = _data[activity_index];
- auto it = std::find(filtered().begin(),
- filtered().end(),
- activity);
+ auto activity_list::index_in_filtered(index_t activity_index) const -> std::optional {
+ auto activity = _data[activity_index];
+ auto it = std::find(filtered().begin(),
+ filtered().end(),
+ activity);
- if (it == filtered().end())
- return std::nullopt;
+ if (it == filtered().end())
+ return std::nullopt;
- return std::distance(filtered().begin(), it);
-}
+ return std::distance(filtered().begin(), it);
+ }
-void stg::activity_list::reset_with(data_t data) {
- activity_list_base::reset_with(data);
+ void activity_list::reset_with(data_t data) {
+ activity_list_base::reset_with(data);
- if (!search_query.empty())
- search(search_query);
-}
+ if (!search_query.empty())
+ search(search_query);
+ }
-const char *stg::activity_list::already_present_exception::what() const noexcept {
- return message;
-}
+ auto activity_list::already_present_exception::what() const noexcept -> const char * {
+ return message;
+ }
+}
\ No newline at end of file
diff --git a/models/activitylist.h b/models/activitylist.h
index e057bb6..33c9772 100644
--- a/models/activitylist.h
+++ b/models/activitylist.h
@@ -18,7 +18,7 @@
namespace stg {
class strategy;
- using activity_index = unsigned int;
+ using activity_index_t = unsigned int;
using activity_list_base = private_list>;
class activity_list :
@@ -32,20 +32,20 @@ namespace stg {
explicit activity_list(const std::vector &from_vector = {});
explicit activity_list(const std::vector> &from_vector);
- const activity &operator[](activity_index item_index) const;
- activity *at(activity_index item_index) const;
+ auto operator[](activity_index_t item_index) const -> const activity &;
+ auto at(activity_index_t item_index) const -> activity *;
- std::optional index_of(const activity *activity) const;
- std::optional index_of(const activity &activity) const;
+ auto index_of(const activity *activity) const -> std::optional;
+ auto index_of(const activity &activity) const -> std::optional;
- bool search(std::string query) const;
- const activity_list::data_t &filtered() const;
- std::optional index_from_filtered(index_t index_in_filtered) const;
- std::optional index_in_filtered(index_t activity_index) const;
+ auto search(std::string query) const -> bool;
+ auto filtered() const -> const activity_list::data_t &;
+ auto index_from_filtered(index_t index_in_filtered) const -> std::optional;
+ auto index_in_filtered(index_t activity_index) const -> std::optional;
void reset_with(data_t data) override;
- std::string class_print_name() const override;
+ auto class_print_name() const -> std::string override;
private:
friend strategy;
@@ -55,21 +55,21 @@ namespace stg {
void silently_add(const activity &activity) noexcept(false);
void add(const activity &activity) noexcept(false);
- void silently_remove_at_index(activity_index index);
- void remove_at_index(activity_index index);
+ void silently_remove_at_index(activity_index_t index);
+ void remove_at_index(activity_index_t index);
- void silently_edit_at_index(activity_index index, const activity &new_activity) noexcept(false);
- void edit_at_index(activity_index index, const activity &new_activity) noexcept(false);
+ void silently_edit_at_index(activity_index_t index, const activity &new_activity) noexcept(false);
+ void edit_at_index(activity_index_t index, const activity &new_activity) noexcept(false);
- void silently_drag(activity_index from_index, activity_index to_index);
- void drag(activity_index from_index, activity_index to_index);
+ void silently_drag(activity_index_t from_index, activity_index_t to_index);
+ void drag(activity_index_t from_index, activity_index_t to_index);
- bool has(const activity &searched_activity) const;
+ auto has(const activity &searched_activity) const -> bool;
};
class activity_list::already_present_exception : public std::exception {
static constexpr auto message = "this activity already exists";
- const char *what() const noexcept override;
+ auto what() const noexcept -> const char * override;
};
}
diff --git a/models/apple/SGCalendarExporter.mm b/models/apple/SGCalendarExporter.mm
index f1ff77d..7638339 100644
--- a/models/apple/SGCalendarExporter.mm
+++ b/models/apple/SGCalendarExporter.mm
@@ -113,7 +113,7 @@ - (void)exportSession:(stg::session *)sessionPtr {
NSString *calendarTitle = self.calendarManager.calendarName;
if (!calendarTitle) {
calendarTitle = [NSString stringWithUTF8String:session.activity->name().c_str()];
- color = CGColorCreateWithHexColorString([NSString stringWithUTF8String:session.activity->color()]);
+ color = session.activity->color().to_cg_color();
}
EKCalendar *calendar = [self.calendarManager findOrCreateCalendarWithTitle:calendarTitle
diff --git a/models/color.cpp b/models/color.cpp
index e5deb74..fd631d4 100644
--- a/models/color.cpp
+++ b/models/color.cpp
@@ -2,4 +2,364 @@
// Created by Dmitry Khrykin on 2020-02-18.
//
+#include
+#include
+#include
+#include
+#include
+#include
+
#include "color.h"
+
+namespace stg {
+ color::color(uint32_t data) :
+ data(data) {
+ }
+
+ color::color(const char *str) :
+ data(parse_hex_string(str)) {
+ }
+
+ color::color(const std::string &str) :
+ data(parse_hex_string(str)) {
+ }
+
+ auto color::operator=(const std::string &str) -> color & {
+ data = parse_hex_string(str);
+
+ return *this;
+ }
+
+ color::operator std::string() const {
+ return to_hex_string();
+ }
+
+ auto operator<<(std::ostream &os, const color &color) -> std::ostream & {
+ os << color.to_hex_string();
+ return os;
+ }
+
+ auto operator==(const color &lhs, const color &rhs) -> bool {
+ return lhs.data == rhs.data;
+ }
+
+ auto operator!=(const color &lhs, const color &rhs) -> bool {
+ return !(lhs == rhs);
+ }
+
+ auto color::to_hex_string() const -> std::string {
+ auto component_string = [](uint8_t value) -> std::string {
+ std::stringstream stream;
+ stream << std::hex
+ << std::setw(2)
+ << std::left
+ << std::setfill('0')
+ << (unsigned) value;
+ return stream.str();
+ };
+
+ std::string result = "#";
+
+ if (alpha() < 255)
+ result += component_string(alpha());
+
+ result = result
+ + component_string(red())
+ + component_string(green())
+ + component_string(blue());
+
+ return result;
+ }
+
+ auto color::parse_hex_string(std::string color_string) -> uint32_t {
+ uint32_t result = 0;
+
+ std::transform(color_string.begin(),
+ color_string.end(),
+ color_string.begin(),
+ tolower);
+
+ color_string = std::regex_replace(color_string, std::regex("^#"), "");
+
+ if (color_string.length() == 3)
+ color_string = {color_string[0],
+ color_string[0],
+ color_string[1],
+ color_string[1],
+ color_string[2],
+ color_string[2]};
+
+
+ if (color_string.length() == 4)
+ color_string = {color_string[0],
+ color_string[0],
+ color_string[1],
+ color_string[1],
+ color_string[2],
+ color_string[2],
+ color_string[3],
+ color_string[3]};
+
+ while (color_string.length() < 6)
+ color_string += "0";
+
+ if (color_string.length() == 6)
+ color_string = "ff" + color_string;
+
+ std::stringstream stream;
+ stream << std::hex << color_string;
+ stream >> result;
+
+ return result;
+ }
+
+ auto color::alpha() const -> uint8_t {
+ return static_cast(data >> 24u) & 255u;
+ }
+
+ auto color::red() const -> uint8_t {
+ return static_cast(data >> 16u) & 255u;
+ }
+
+ auto color::green() const -> uint8_t {
+ return static_cast(data >> 8u) & 255u;
+ }
+
+ auto color::blue() const -> uint8_t {
+ return data & 255u;
+ }
+
+ auto color::red_component() const -> float {
+ return static_cast(red()) / 255u;
+ }
+
+ auto color::green_component() const -> float {
+ return static_cast(green()) / 255u;
+ }
+
+ auto color::blue_component() const -> float {
+ return static_cast(blue()) / 255u;
+ }
+
+ auto color::alpha_component() const -> float {
+ return static_cast(alpha()) / 255u;
+ }
+
+ void color::set_alpha(uint8_t value) {
+ data = (data & 0x00'ff'ff'ffu) | static_cast(value << 24u);
+ }
+
+ void color::set_red(uint8_t value) {
+ data = (data & 0xff'00'ff'ffu) | static_cast(value << 16u);
+ }
+
+ void color::set_green(uint8_t value) {
+ data = (data & 0xff'ff'00'ffu) | static_cast(value << 8u);
+ }
+
+ void color::set_blue(uint8_t value) {
+ data = (data & 0xff'ff'ff'00u) | static_cast(value);
+ }
+
+ void color::set_red_component(float value) {
+ set_red(std::round(value * 255u));
+ }
+
+ void color::set_green_component(float value) {
+ set_green(std::round(value * 255u));
+ }
+
+ void color::set_blue_component(float value) {
+ set_blue(std::round(value * 255u));
+ }
+
+ void color::set_alpha_component(float value) {
+ set_alpha(std::round(value * 255u));
+ }
+
+ void color::set_hsl(float hue, float saturation, float lightness) {
+ hue = hue * 360 / 60;
+
+ auto chroma = (1 - std::abs(2 * lightness - 1)) * saturation;
+ auto x = chroma * (1 - std::abs(std::fmodf(hue, 2) - 1));
+
+ auto rgb = std::array();
+
+ if (std::ceilf(hue) == 1) {
+ rgb = {chroma, x, 0};
+ } else if (std::ceilf(hue) == 2) {
+ rgb = {x, chroma, 0};
+ } else if (std::ceilf(hue) == 3) {
+ rgb = {0, chroma, x};
+ } else if (std::ceilf(hue) == 4) {
+ rgb = {0, x, chroma};
+ } else if (std::ceilf(hue) == 5) {
+ rgb = {x, 0, chroma};
+ } else if (std::ceilf(hue) == 6) {
+ rgb = {chroma, 0, x};
+ }
+
+ auto m = lightness - 0.5 * chroma;
+ std::transform(rgb.begin(),
+ rgb.end(),
+ rgb.begin(), [&m](auto &c) {
+ return c + m;
+ });
+
+ set_red_component(rgb[0]);
+ set_green_component(rgb[1]);
+ set_blue_component(rgb[2]);
+ }
+
+ auto color::lightness() const -> float {
+ auto x_max = std::max({red_component(),
+ green_component(),
+ blue_component()});
+
+ auto x_min = std::min({red_component(),
+ green_component(),
+ blue_component()});
+
+ return 0.5f * (x_max + x_min);
+ }
+
+ auto color::hue() const -> float {
+ auto chroma = chroma_range();
+ auto value = brightness();
+
+ auto result = 0.0f;
+ if (chroma == 0) {
+ return result;
+ } else if (value == red_component()) {
+ auto shift = blue_component() > green_component() ? 6 : 0;
+ result = 1.0f / 6 * (shift + (green_component() - blue_component()) / chroma);
+ } else if (value == green_component()) {
+ result = 1.0f / 6 * (2 + (blue_component() - red_component()) / chroma);
+ } else if (value == blue_component()) {
+ result = 1.0f / 6 * (4 + (red_component() - green_component()) / chroma);
+ }
+
+ return result;
+ }
+
+ auto color::saturation() const -> float {
+ if (lightness() == 0 || lightness() == 1) {
+ return 0;
+ } else {
+ auto chroma = chroma_range();
+ return chroma / (1 - std::abs(2 * brightness() - chroma - 1));
+ }
+ }
+
+ auto color::brightness() const -> float {
+ return std::max({red_component(),
+ green_component(),
+ blue_component()});
+ }
+
+ auto color::chroma_range() const -> float {
+ auto x_max = brightness();
+ auto x_min = std::min({red_component(),
+ green_component(),
+ blue_component()});
+ return x_max - x_min;
+ }
+
+ auto color::components() const -> std::array {
+ return {red_component(),
+ green_component(),
+ blue_component(),
+ alpha_component()};
+ }
+
+ void color::blend_with(const color &overlay_color) {
+ auto new_red_component = red_component()
+ + (overlay_color.red_component() - red_component())
+ * overlay_color.alpha_component();
+
+ set_red_component(new_red_component);
+
+ auto new_green_component = green_component()
+ + (overlay_color.green_component() - green_component())
+ * overlay_color.alpha_component();
+
+ set_green_component(new_green_component);
+
+ auto new_blue_component = blue_component()
+ + (overlay_color.blue_component() - blue_component())
+ * overlay_color.alpha_component();
+
+ set_blue_component(new_blue_component);
+ }
+
+ color::color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
+ set_rgba(red, green, blue, alpha);
+ }
+
+ void color::set_rgba(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
+ data = 0u;
+ data = data | static_cast(alpha << 24u);
+ data = data | static_cast(red << 16u);
+ data = data | static_cast(green << 8u);
+ data = data | static_cast(blue);
+ }
+
+ auto color::info() const -> std::string {
+ std::stringstream s;
+ s << "color: " << *this << " "
+ << "rgba(" << (int) red()
+ << ", " << (int) green()
+ << ", " << (int) blue()
+ << "," << (int) alpha() << ") "
+ << "hslb(" << hue() * 360
+ << "°, " << saturation()
+ << ", " << lightness()
+ << ", " << brightness() << ")";
+
+ return s.str();
+ }
+
+ auto color::blended_with(const color &overlay_color) const -> color {
+ auto clr = *this;
+ clr.blend_with(overlay_color);
+
+ return clr;
+ }
+
+ auto color::with_alpha_component(float value) const -> color {
+ auto clr = *this;
+ clr.set_alpha_component(value);
+
+ return clr;
+ }
+
+ auto color::with_hsl(float hue, float saturation, float lightness) const -> color {
+ auto clr = *this;
+ clr.set_hsl(hue, saturation, lightness);
+
+ return clr;
+ }
+
+ void color::invert() {
+ data = ~data;
+ }
+
+ auto color::inverted() -> color {
+ auto clr = *this;
+ clr.invert();
+
+ return clr;
+ }
+
+ auto color::clear_color() -> color {
+ return color(0x00'00'00'00u);
+ }
+
+ auto color::black_color() -> color {
+ return color(0xff'00'00'00u);
+ }
+
+ auto color::white_color() -> color {
+ return color(0xff'ff'ff'ffu);
+ }
+}
diff --git a/models/color.h b/models/color.h
index 816c870..f963479 100644
--- a/models/color.h
+++ b/models/color.h
@@ -7,59 +7,108 @@
#include
#include
-#include
+#include
#include
+struct CGColor;
namespace stg {
struct color {
- color() {
- init("#000000");
- }
+ template
+ struct is_qcolor_like : std::false_type {
+ };
- color(const char *str) {
- init(str);
- }
+ template
+ struct is_qcolor_like().red()),
+ decltype(std::declval().green()),
+ decltype(std::declval().blue()),
+ decltype(std::declval().alpha())> : std::true_type {
+ };
- color(const std::string &str) {
- init(str);
- }
+ explicit color(uint32_t data = 0xff000000);
- color &operator=(const std::string &str) {
- init(str);
- return *this;
- }
+ color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255);
- operator const char *() const {
- return color_string.c_str();
- }
+ color(const char *str);
+ color(const std::string &str);
- operator const std::string &() const {
- return color_string;
+ template::value, int> = 0>
+ color(const T &q_color_like) {
+ set_rgba(q_color_like.red(),
+ q_color_like.green(),
+ q_color_like.blue(),
+ q_color_like.alpha());
}
- private:
- friend std::ostream &operator<<(std::ostream &os, const color &color) {
- os << color.color_string;
- return os;
- }
+ auto operator=(const std::string &str) -> color &;
+ operator std::string() const;
- friend bool operator==(const stg::color &lhs, const stg::color &rhs) {
- return lhs.color_string == rhs.color_string;
+ template::value, int> = 0>
+ operator T() const {
+ return T(red(), green(), blue(), alpha());
}
- friend bool operator!=(const stg::color &lhs, const stg::color &rhs) {
- return !(lhs == rhs);
- }
+ static auto clear_color() -> color;
+ static auto black_color() -> color;
+ static auto white_color() -> color;
- std::string color_string;
+ auto red() const -> uint8_t;
+ auto green() const -> uint8_t;
+ auto blue() const -> uint8_t;
+ auto alpha() const -> uint8_t;
- void init(const std::string &str) {
- color_string = str;
- std::transform(color_string.begin(),
- color_string.end(),
- color_string.begin(),
- tolower);
- }
+ auto red_component() const -> float;
+ auto green_component() const -> float;
+ auto blue_component() const -> float;
+ auto alpha_component() const -> float;
+
+ void set_red(uint8_t value);
+ void set_green(uint8_t value);
+ void set_blue(uint8_t value);
+ void set_alpha(uint8_t value);
+
+ void set_red_component(float value);
+ void set_green_component(float value);
+ void set_blue_component(float value);
+ void set_alpha_component(float value);
+
+ void set_rgba(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255);
+ void set_hsl(float hue, float saturation, float lightness);
+ auto with_hsl(float hue, float saturation, float lightness) const -> color;
+
+ auto hue() const -> float;
+ auto saturation() const -> float;
+ auto lightness() const -> float;
+ auto brightness() const -> float;
+
+ void blend_with(const color &overlay_color);
+ auto blended_with(const color &overlay_color) const -> color;
+ auto with_alpha_component(float value) const -> color;
+
+ void invert();
+ auto inverted() -> color;
+
+ auto components() const -> std::array;
+ auto info() const -> std::string;
+
+ auto to_cg_color() const -> CGColor *;
+ static auto from_cg_color(CGColor *cg_color) -> color;
+
+ auto to_hex_string() const -> std::string;
+ private:
+ uint32_t data = 0;
+
+ auto chroma_range() const -> float;
+
+ static auto parse_hex_string(std::string color_string) -> uint32_t;
+
+ friend auto operator<<(std::ostream &os, const color &color) -> std::ostream &;
+ friend auto operator==(const stg::color &lhs, const stg::color &rhs) -> bool;
+ friend auto operator!=(const stg::color &lhs, const stg::color &rhs) -> bool;
};
}
diff --git a/models/color.mm b/models/color.mm
new file mode 100644
index 0000000..c86f986
--- /dev/null
+++ b/models/color.mm
@@ -0,0 +1,46 @@
+//
+// Created by Dmitry Khrykin on 26/04/2020.
+//
+
+#import
+#include
+
+#include "color.h"
+
+namespace stg {
+ auto color::to_cg_color() const -> struct CGColor * {
+ auto color_space = CGColorSpaceCreateDeviceRGB();
+ auto cg_color = CGColorCreate(color_space, components().data());
+ CGColorSpaceRelease(color_space);
+ return cg_color;
+ }
+
+ auto color::from_cg_color(CGColor *cg_color) -> color {
+ const auto *components = CGColorGetComponents(cg_color);
+ auto color_space_model = CGColorSpaceGetModel(CGColorGetColorSpace(cg_color));
+
+ if (color_space_model != kCGColorSpaceModelRGB
+ && color_space_model != kCGColorSpaceModelMonochrome) {
+ auto color_space = CGColorSpaceCreateDeviceRGB();
+ cg_color = CGColorCreateCopyByMatchingToColorSpace(color_space, kCGRenderingIntentDefault, cg_color, nil);
+ color_space_model = kCGColorSpaceModelRGB;
+ }
+
+ if (color_space_model == kCGColorSpaceModelRGB) {
+ return color(static_cast(255u * components[0]),
+ static_cast(255u * components[1]),
+ static_cast(255u * components[2]),
+ static_cast(255u * components[3]));
+
+ } else if (color_space_model == kCGColorSpaceModelMonochrome) {
+ return color(static_cast(255u * components[0]),
+ static_cast(255u * components[0]),
+ static_cast(255u * components[0]));
+ } else {
+ std::cout << "stg::color Warning: Can't convert from CGColor: unsupported color space\n";
+
+ return color();
+ }
+ }
+
+}
diff --git a/models/currenttimemarker.cpp b/models/currenttimemarker.cpp
index 7152a23..14f2b06 100644
--- a/models/currenttimemarker.cpp
+++ b/models/currenttimemarker.cpp
@@ -39,15 +39,15 @@ auto stg::current_time_marker::rect_in_parent(const rect &parent_rect,
};
}
-auto stg::current_time_marker::scroll_offset_in_parent(const rect &parent_rect,
- int window_height) const -> int {
- auto rect = rect_in_parent(parent_rect);
- auto top_offset = rect.top - window_height / 2;
+auto stg::current_time_marker::scroll_offset(const rect &slots_rect,
+ int viewport_height) const -> int {
+ auto rect = rect_in_parent(slots_rect);
+ auto top_offset = rect.top - viewport_height / 2;
if (top_offset < 0) {
top_offset = 0;
- } else if (top_offset > parent_rect.height) {
- top_offset = parent_rect.height;
+ } else if (top_offset > slots_rect.height - viewport_height) {
+ top_offset = slots_rect.height - viewport_height;
}
return top_offset;
diff --git a/models/currenttimemarker.h b/models/currenttimemarker.h
index c91a1cf..639b69b 100644
--- a/models/currenttimemarker.h
+++ b/models/currenttimemarker.h
@@ -20,8 +20,8 @@ namespace stg {
auto rect_in_parent(const rect &parent_rect,
int marker_radius = 0) const -> rect;
- auto scroll_offset_in_parent(const rect &parent_rect,
- int window_height) const -> int;
+ auto scroll_offset(const rect &slots_rect,
+ int viewport_height) const -> int;
private:
const strategy &strategy;
diff --git a/models/dragoperation.cpp b/models/dragoperation.cpp
index bb92f14..39d1ffe 100644
--- a/models/dragoperation.cpp
+++ b/models/dragoperation.cpp
@@ -5,334 +5,325 @@
#include "dragoperation.h"
#include "strategy.h"
-stg::drag_operation::drag_operation(time_slots_state *time_slots, indices_vector initial_indices)
- : time_slots(time_slots),
- initial_dragged_indices(std::move(initial_indices)) {
-}
-
-std::vector
-stg::drag_operation::record_drag(const std::vector &time_slots_to_drag, int distance) {
- if (distance == 0) {
- return {};
+namespace stg {
+ drag_operation::drag_operation(time_slots_state *time_slots, indices_vector initial_indices)
+ : time_slots(time_slots),
+ initial_dragged_indices(std::move(initial_indices)) {
}
- auto range_to_drag = indices_range{*time_slots->index_of(time_slots_to_drag.front()),
- *time_slots->index_of(time_slots_to_drag.back())};
-
- // Drag operation_type is divided into two phases:
- // 1. Drag selected slots to their new positions, switching the nearby slots;
- auto new_dragged_indices = silently_drag(range_to_drag, distance);
- // 2. Try to restore nearby sessions' initial positions.
- invalidate_drag(new_dragged_indices);
+ auto drag_operation::record_drag(const std::vector &time_slots_to_drag,
+ int distance) -> std::vector {
+ if (distance == 0) {
+ return {};
+ }
- return new_dragged_indices;
-}
+ auto range_to_drag = indices_range{*time_slots->index_of(time_slots_to_drag.front()),
+ *time_slots->index_of(time_slots_to_drag.back())};
-stg::drag_operation::indices_vector
-stg::drag_operation::silently_drag(const indices_range &range_to_drag, int distance) {
- auto destination_index = distance < 0
- ? range_to_drag.first + distance
- : range_to_drag.last + distance;
+ // Drag operation_type is divided into two phases:
+ // 1. Drag selected slots to their new positions, switching the nearby slots;
+ auto new_dragged_indices = silently_drag(range_to_drag, distance);
+ // 2. Try to restore nearby sessions' initial positions.
+ invalidate_drag(new_dragged_indices);
- if (destination_index > time_slots->size() - 1) {
- return {};
+ return new_dragged_indices;
}
- auto[cache_range, restore_cache_range, new_drag_range]
- = get_ranges(range_to_drag, destination_index, distance);
-
- auto cache = make_cache(cache_range);
+ auto drag_operation::silently_drag(const indices_range &range_to_drag,
+ int distance) -> indices_vector {
+ auto destination_index = distance < 0
+ ? range_to_drag.first + distance
+ : range_to_drag.last + distance;
- movements_state movements;
- indices_vector new_dragged_indices;
+ if (destination_index > time_slots->size() - 1) {
+ return {};
+ }
- for (auto i = 0; i < range_to_drag.size(); i++) {
- auto insert_at_index = new_drag_range.first + i;
- auto old_index = range_to_drag.first + i;
+ auto[cache_range, restore_cache_range, new_drag_range]
+ = get_ranges(range_to_drag, destination_index, distance);
- movements[old_index] = insert_at_index;
+ auto cache = make_cache(cache_range);
- new_dragged_indices.push_back(insert_at_index);
+ movements_state movements;
+ indices_vector new_dragged_indices;
- auto activity_at_old_index = time_slots->at(old_index).activity;
- time_slots->silently_set_activity_at_index(insert_at_index,
- activity_at_old_index);
- }
+ for (auto i = 0; i < range_to_drag.size(); i++) {
+ auto insert_at_index = new_drag_range.first + i;
+ auto old_index = range_to_drag.first + i;
- restore_cache(restore_cache_range, cache, movements);
+ movements[old_index] = insert_at_index;
- apply_movements_to_history(movements);
+ new_dragged_indices.push_back(insert_at_index);
- return new_dragged_indices;
-}
+ auto activity_at_old_index = time_slots->at(old_index).activity;
+ time_slots->silently_set_activity_at_index(insert_at_index,
+ activity_at_old_index);
+ }
-void stg::drag_operation::restore_cache(const indices_range &restore_cache_range,
- const indices_cache &cache,
- movements_state &movements) const {
- for (size_t i = 0; i < cache.size(); i++) {
- auto insert_at_index = static_cast(restore_cache_range.first + i);
- auto[history_index, activity] = cache[i];
+ restore_cache(restore_cache_range, cache, movements);
- movements[history_index] = insert_at_index;
+ apply_movements_to_history(movements);
- time_slots->silently_set_activity_at_index(insert_at_index, activity);
- }
-}
-
-std::tuple<
- stg::drag_operation::indices_range,
- stg::drag_operation::indices_range,
- stg::drag_operation::indices_range
->
-stg::drag_operation::get_ranges(const indices_range &indices_to_drag,
- index_t destination_index,
- int distance) const {
- auto cache_range = get_cache_range(indices_to_drag,
- destination_index,
- distance);
-
- auto restore_cache_first_index = distance < 0
- ? destination_index + indices_to_drag.size()
- : indices_to_drag.first;
-
- auto restore_cache_range = indices_range{restore_cache_first_index,
- restore_cache_first_index + cache_range.size()};
-
- auto new_drag_range = get_new_dragging_indices(indices_to_drag,
- destination_index,
- distance);
-
- return std::make_tuple(cache_range, restore_cache_range, new_drag_range);
-}
-
-stg::drag_operation::indices_range
-stg::drag_operation::get_new_dragging_indices(const indices_range &dragging_indices,
- index_t destination_index,
- int distance) const {
- auto new_first_index = distance < 0
- ? destination_index
- : destination_index - dragging_indices.size() + 1;
-
- return indices_range{new_first_index,
- new_first_index + dragging_indices.size()};
-}
-
-stg::drag_operation::indices_range
-stg::drag_operation::get_cache_range(const indices_range &dragging_indices,
- index_t destination_index,
- int distance) const {
- return distance < 0
- ? indices_range{destination_index,
- dragging_indices.first - 1}
- : indices_range{dragging_indices.last + 1,
- destination_index};
-}
-
-stg::drag_operation::indices_cache
-stg::drag_operation::make_cache(indices_range cache_indices) const {
- indices_cache cache = {};
-
- for (auto i = cache_indices.first; i <= cache_indices.last; i++) {
- auto cache_entry = std::make_tuple(i, time_slots->at(i).activity);
- cache.push_back(cache_entry);
+ return new_dragged_indices;
}
- return cache;
-}
+ void drag_operation::restore_cache(const indices_range &restore_cache_range,
+ const indices_cache &cache,
+ movements_state &movements) const {
+ for (size_t i = 0; i < cache.size(); i++) {
+ auto insert_at_index = static_cast(restore_cache_range.first + i);
+ auto[history_index, activity] = cache[i];
-void stg::drag_operation::invalidate_drag(const indices_vector &dragged_indices) {
- if (dragged_indices.empty()) {
- return;
+ movements[history_index] = insert_at_index;
+
+ time_slots->silently_set_activity_at_index(insert_at_index, activity);
+ }
}
- auto nobody_can_move = false;
+ auto drag_operation::get_ranges(const indices_range &indices_to_drag,
+ index_t destination_index,
+ int distance) const -> ranges_tuple {
+ auto cache_range = get_cache_range(indices_to_drag,
+ destination_index,
+ distance);
- while (!nobody_can_move) {
- auto cant_move_count = 0;
+ auto restore_cache_first_index = distance < 0
+ ? destination_index + indices_to_drag.size()
+ : indices_to_drag.first;
- for (auto const&[current_index, past_indices] : history) {
- auto slot_is_dragged = std::find(dragged_indices.begin(),
- dragged_indices.end(),
- current_index) != dragged_indices.end();
+ auto restore_cache_range = indices_range{restore_cache_first_index,
+ restore_cache_first_index + cache_range.size()};
- auto slot_is_empty = time_slots->at(current_index).activity == strategy::no_activity;
+ auto new_drag_range = get_new_dragging_indices(indices_to_drag,
+ destination_index,
+ distance);
- if (slot_is_dragged || slot_is_empty) {
- cant_move_count++;
- continue;
- }
+ return std::make_tuple(cache_range, restore_cache_range, new_drag_range);
+ }
- auto session_range = find_session_range_for(current_index);
+ auto drag_operation::get_new_dragging_indices(const indices_range &dragging_indices,
+ index_t destination_index,
+ int distance) -> indices_range {
+ auto new_first_index = distance < 0
+ ? destination_index
+ : destination_index - dragging_indices.size() + 1;
- auto initial_session_begin_index = get_initial(session_range.first);
+ return indices_range{new_first_index,
+ new_first_index + dragging_indices.size()};
+ }
- if (initial_session_begin_index != session_range.first) {
- auto can_move_to = find_avaliable_movement_index(session_range,
- initial_session_begin_index);
+ auto drag_operation::get_cache_range(const indices_range &dragging_indices,
+ index_t destination_index,
+ int distance) -> indices_range {
+ return distance < 0
+ ? indices_range{destination_index,
+ dragging_indices.first - 1}
+ : indices_range{dragging_indices.last + 1,
+ destination_index};
+ }
- if (can_move_to != session_range.first) {
- auto distance = can_move_to - session_range.first;
- silently_drag(session_range, distance);
- break;
- }
- }
+ auto drag_operation::make_cache(indices_range cache_indices) const -> indices_cache {
+ indices_cache cache = {};
- cant_move_count++;
+ for (auto i = cache_indices.first; i <= cache_indices.last; i++) {
+ auto cache_entry = std::make_tuple(i, time_slots->at(i).activity);
+ cache.push_back(cache_entry);
}
- if (cant_move_count == history.size()) {
- nobody_can_move = true;
- }
+ return cache;
}
-}
-stg::drag_operation::index_t
-stg::drag_operation::get_initial(index_t index) {
- return history.count(index)
- ? history[index][initial_index_key]
- : index;
-}
+ void stg::drag_operation::invalidate_drag(const indices_vector &dragged_indices) {
+ if (dragged_indices.empty()) {
+ return;
+ }
-void stg::drag_operation::print_indices(const std::string &name,
- const indices_vector &indices_state) {
- std::cout << name << ": [ ";
+ auto nobody_can_move = false;
- for (auto index : indices_state) {
- std::cout << index << " ";
- }
+ while (!nobody_can_move) {
+ auto cant_move_count = 0;
- std::cout << "]" << std::endl;
-}
+ for (auto const&[current_index, past_indices] : history) {
+ auto slot_is_dragged = std::find(dragged_indices.begin(),
+ dragged_indices.end(),
+ current_index) != dragged_indices.end();
-void stg::drag_operation::print_history(const std::string &name,
- const history_state &history_state) {
- std::cout << name << std::endl;
- for (auto const&[current_index, past_indices] : history_state) {
- if (!past_indices.empty()) {
- print_indices(std::to_string(current_index), past_indices);
- }
- }
-}
+ auto slot_is_empty = time_slots->at(current_index).activity == strategy::no_activity;
-void stg::drag_operation::print_movements(const movements_state &movements) {
- std::cout << "movements:" << std::endl;
- for (auto const&[past_index, current_index] : movements) {
- std::cout << past_index << " -> " << current_index << std::endl;
- }
-}
+ if (slot_is_dragged || slot_is_empty) {
+ cant_move_count++;
+ continue;
+ }
-void stg::drag_operation::apply_movements_to_history(const movements_state &movements) {
- history_state new_history_stacks;
+ auto session_range = find_session_range_for(current_index);
- for (auto const&[past_index, current_index] : movements) {
- auto new_history_stack = history[past_index];
- new_history_stack.push_back(past_index);
+ auto initial_session_begin_index = get_initial(session_range.first);
- new_history_stacks[current_index] = new_history_stack;
- }
+ if (initial_session_begin_index != session_range.first) {
+ auto can_move_to = find_avaliable_movement_index(session_range,
+ initial_session_begin_index);
- for (auto const&[index, stack] : new_history_stacks) {
- if (index == stack.front()) {
- history.erase(index);
- } else {
- indices_vector history_entry{stack.front()};
+ if (can_move_to != session_range.first) {
+ auto distance = can_move_to - session_range.first;
+ silently_drag(session_range, distance);
+ break;
+ }
+ }
- // history entry doesn't need more than two values:
- // only initial index and previous index if they're different
- if (stack.back() != stack.front()) {
- history_entry.push_back(stack.back());
+ cant_move_count++;
}
- history[index] = history_entry;
+ if (cant_move_count == history.size()) {
+ nobody_can_move = true;
+ }
}
}
-}
-
-stg::drag_operation::indices_range
-stg::drag_operation::find_session_range_for(index_t time_slot_index) {
- if (time_slot_index < 0)
- time_slot_index = 0;
- if (time_slot_index > time_slots->size() - 1) {
- time_slot_index = time_slots->size() - 1;
+
+ auto drag_operation::get_initial(index_t index) -> index_t {
+ return history.count(index)
+ ? history[index][initial_index_key]
+ : index;
}
- auto begin_index = time_slot_index;
- auto end_index = time_slot_index;
+ void drag_operation::print_indices(const std::string &name,
+ const indices_vector &indices_state) {
+ std::cout << name << ": [ ";
- for (auto i = time_slot_index; i > 0; i--) {
- if (time_slots->at(i).activity == time_slots->at(time_slot_index).activity) {
- begin_index = i;
- } else {
- break;
+ for (auto index : indices_state) {
+ std::cout << index << " ";
}
+
+ std::cout << "]" << std::endl;
}
- for (auto i = time_slot_index; i < time_slots->size(); i++) {
- if (time_slots->at(i).activity == time_slots->at(time_slot_index).activity) {
- end_index = i;
- } else {
- break;
+ void drag_operation::print_history(const std::string &name,
+ const history_state &history_state) {
+ std::cout << name << std::endl;
+ for (auto const&[current_index, past_indices] : history_state) {
+ if (!past_indices.empty()) {
+ print_indices(std::to_string(current_index), past_indices);
+ }
}
}
- return indices_range{begin_index, end_index};
-}
+ void drag_operation::print_movements(const movements_state &movements) {
+ std::cout << "movements:" << std::endl;
+ for (auto const&[past_index, current_index] : movements) {
+ std::cout << past_index << " -> " << current_index << std::endl;
+ }
+ }
-stg::drag_operation::index_t
-stg::drag_operation::find_avaliable_movement_index(indices_range session_range,
- index_t target_index) {
- index_t result = session_range.first;
+ void drag_operation::apply_movements_to_history(const movements_state &movements) {
+ history_state new_history_stacks;
- auto wants_up = session_range.first > target_index;
- auto wants_down = session_range.first < target_index;
+ for (auto const&[past_index, current_index] : movements) {
+ auto new_history_stack = history[past_index];
+ new_history_stack.push_back(past_index);
- if (wants_up) {
- if (session_range.first == 0) {
- return result;
+ new_history_stacks[current_index] = new_history_stack;
}
- for (auto i = session_range.first - 1; i >= target_index; i--) {
- if (time_slots->at(i).activity == strategy::no_activity ||
- time_slots->at(i).activity == time_slots->at(session_range.first).activity) {
- result = i;
+ for (auto const&[index, stack] : new_history_stacks) {
+ if (index == stack.front()) {
+ history.erase(index);
} else {
- break;
+ indices_vector history_entry{stack.front()};
+
+ // history entry doesn't need more than two values:
+ // only initial index and previous index if they're different
+ if (stack.back() != stack.front()) {
+ history_entry.push_back(stack.back());
+ }
+
+ history[index] = history_entry;
}
}
}
- if (wants_down) {
- if (session_range.last == time_slots->size() - 1 ||
- target_index + session_range.size() >= time_slots->size()) {
- return result;
+ auto drag_operation::find_session_range_for(index_t time_slot_index) -> indices_range {
+ if (time_slot_index < 0)
+ time_slot_index = 0;
+ if (time_slot_index > time_slots->size() - 1) {
+ time_slot_index = time_slots->size() - 1;
+ }
+
+ auto begin_index = time_slot_index;
+ auto end_index = time_slot_index;
+
+ for (auto i = time_slot_index; i > 0; i--) {
+ if (time_slots->at(i).activity == time_slots->at(time_slot_index).activity) {
+ begin_index = i;
+ } else {
+ break;
+ }
}
- for (auto i = session_range.last + 1; i <= target_index + session_range.size() - 1; i++) {
- if (time_slots->at(i).activity == strategy::no_activity ||
- time_slots->at(i).activity == time_slots->at(session_range.last).activity) {
- result = i - session_range.size() + 1;
+ for (auto i = time_slot_index; i < time_slots->size(); i++) {
+ if (time_slots->at(i).activity == time_slots->at(time_slot_index).activity) {
+ end_index = i;
} else {
break;
}
}
+
+ return indices_range{begin_index, end_index};
}
- return result;
-}
+ auto drag_operation::find_avaliable_movement_index(indices_range session_range,
+ index_t target_index) -> index_t {
+ index_t result = session_range.first;
+
+ auto wants_up = session_range.first > target_index;
+ auto wants_down = session_range.first < target_index;
+
+ if (wants_up) {
+ if (session_range.first == 0) {
+ return result;
+ }
+
+ for (auto i = session_range.first - 1; i >= target_index; i--) {
+ if (time_slots->at(i).activity == strategy::no_activity ||
+ time_slots->at(i).activity == time_slots->at(session_range.first).activity) {
+ result = i;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (wants_down) {
+ if (session_range.last == time_slots->size() - 1 ||
+ target_index + session_range.size() >= time_slots->size()) {
+ return result;
+ }
+
+ for (auto i = session_range.last + 1; i <= target_index + session_range.size() - 1; i++) {
+ if (time_slots->at(i).activity == strategy::no_activity ||
+ time_slots->at(i).activity == time_slots->at(session_range.last).activity) {
+ result = i - session_range.size() + 1;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
-bool stg::drag_operation::state_changed() {
- return time_slots->data() != initial_time_slots;
-}
+ auto drag_operation::state_changed() -> bool {
+ return time_slots->data() != initial_time_slots;
+ }
-stg::time_slots_state::data_t &stg::drag_operation::initial_state() {
- return initial_time_slots;
-}
+ auto drag_operation::initial_state() -> time_slots_state::data_t & {
+ return initial_time_slots;
+ }
-stg::drag_operation::index_t stg::drag_operation::indices_range::size() const {
- return last - first + 1;
-}
+ drag_operation::indices_range::indices_range(index_t frst, index_t lst) {
+ first = frst < 0 ? 0 : frst;
+ last = lst < 0 ? 0 : lst;
+ }
-stg::drag_operation::indices_range::indices_range(index_t frst, index_t lst) {
- first = frst < 0 ? 0 : frst;
- last = lst < 0 ? 0 : lst;
-}
+ auto drag_operation::indices_range::size() const -> index_t {
+ return last - first + 1;
+ }
+}
\ No newline at end of file
diff --git a/models/dragoperation.h b/models/dragoperation.h
index add3177..78e7c04 100644
--- a/models/dragoperation.h
+++ b/models/dragoperation.h
@@ -33,30 +33,32 @@ namespace stg {
explicit drag_operation(time_slots_state *time_slots,
indices_vector initial_indices);
- std::vector record_drag(const std::vector &time_slots_to_drag,
- int distance);
+ auto record_drag(const std::vector &time_slots_to_drag,
+ int distance) -> std::vector;
- bool state_changed();
+ auto state_changed() -> bool;
- time_slots_state::data_t &initial_state();
+ auto initial_state() -> time_slots_state::data_t &;
private:
- static const unsigned int initial_index_key = 0;
-
struct indices_range {
indices_range(index_t frst, index_t lst);
index_t first = 0;
index_t last = 0;
- index_t size() const;
+ auto size() const -> index_t;
- friend std::ostream &operator<<(std::ostream &os,
- const indices_range &r) {
+ friend auto operator<<(std::ostream &os,
+ const indices_range &r) -> std::ostream & {
os << "[" << r.first << ", " << r.last << "]";
return os;
}
};
+ using ranges_tuple = std::tuple;
+
+ static const unsigned int initial_index_key = 0;
+
time_slots_state *time_slots;
time_slots_state::data_t initial_time_slots = time_slots->data();
@@ -64,44 +66,41 @@ namespace stg {
history_state history = history_state();
- indices_vector silently_drag(const indices_range &range_to_drag,
- int distance);
+ auto silently_drag(const indices_range &range_to_drag,
+ int distance) -> indices_vector;
void restore_cache(const indices_range &restore_cache_range,
const indices_cache &cache,
movements_state &movements) const;
- std::tuple
- get_ranges(const indices_range &indices_to_drag,
- index_t destination_index,
- int distance) const;
+ auto get_ranges(const indices_range &indices_to_drag,
+ index_t destination_index,
+ int distance) const -> ranges_tuple;
- indices_range get_new_dragging_indices(const indices_range &dragging_indices,
- index_t destination_index,
- int distance) const;
+ static auto get_new_dragging_indices(const indices_range &dragging_indices,
+ index_t destination_index,
+ int distance) -> indices_range;
- indices_range get_cache_range(const indices_range &dragging_indices,
- index_t destination_index,
- int distance) const;
+ static auto get_cache_range(const indices_range &dragging_indices,
+ index_t destination_index,
+ int distance) -> indices_range;
- indices_cache make_cache(indices_range cache_indices) const;
+ auto make_cache(indices_range cache_indices) const -> indices_cache;
void apply_movements_to_history(const movements_state &movements);
void invalidate_drag(const indices_vector &new_dragged_indices);
- indices_range find_session_range_for(index_t time_slot_index);
- index_t find_avaliable_movement_index(indices_range session_range,
- index_t target_index);
+ auto find_session_range_for(index_t time_slot_index) -> indices_range;
+ auto find_avaliable_movement_index(indices_range session_range,
+ index_t target_index) -> index_t;
- index_t get_initial(index_t index);
+ auto get_initial(index_t index) -> index_t;
+ static void print_history(const std::string &name,
+ const history_state &history_state);
static void print_indices(const std::string &name,
const indices_vector &indices_state);
-
-
- void print_history(const std::string &name,
- const history_state &history_state);
static void print_movements(const movements_state &movements);
};
}
diff --git a/models/event.cpp b/models/event.cpp
index a5c75b0..fc35625 100644
--- a/models/event.cpp
+++ b/models/event.cpp
@@ -14,15 +14,15 @@ stg::mouse_event::mouse_event(const stg::point &position,
position(position) {
}
-bool stg::event::has_only(stg::event::key_modifiers mod) const {
+auto stg::event::has_only(stg::event::key_modifiers mod) const -> bool {
return modifiers == mod;
}
-bool stg::event::with(stg::event::key_modifiers mod) const {
+auto stg::event::with(stg::event::key_modifiers mod) const -> bool {
return (modifiers & mod) == mod;
}
-std::ostream &stg::operator<<(std::ostream &os, const stg::mouse_event &e) {
+auto stg::operator<<(std::ostream &os, const stg::mouse_event &e) -> std::ostream & {
os << "mouse_event {\n";
os << " position: [" << e.position.x << ", " << e.position.y << "]\n";
os << " modifiers: [";
diff --git a/models/event.h b/models/event.h
index 3bb976d..25f9fc1 100644
--- a/models/event.h
+++ b/models/event.h
@@ -9,7 +9,7 @@
namespace stg {
struct event {
- using key_modifiers = uint8_t;
+ using key_modifiers = uint16_t;
static constexpr key_modifiers left_key = 1u << 0u;
static constexpr key_modifiers right_key = 1u << 1u;
@@ -34,13 +34,15 @@ namespace stg {
}
}
- bool has_only(key_modifiers mod) const;
- bool with(key_modifiers mod) const;
+ auto has_only(key_modifiers mod) const -> bool;
+ auto with(key_modifiers mod) const -> bool;
key_modifiers modifiers = 0;
};
struct mouse_event : public event {
+ point position;
+
explicit mouse_event(const point &position, key_modifiers modifiers = left_key);
template
@@ -52,8 +54,7 @@ namespace stg {
}
}
- friend std::ostream &operator<<(std::ostream &os, const mouse_event &e);
- point position;
+ friend auto operator<<(std::ostream &os, const mouse_event &e) -> std::ostream &;
};
};
diff --git a/models/geometry.h b/models/geometry.h
index 60708d3..6d7f167 100644
--- a/models/geometry.h
+++ b/models/geometry.h
@@ -81,11 +81,11 @@ namespace stg {
static_cast(y)};
}
- point operator+(const point &other) const {
+ auto operator+(const point &other) const -> point {
return point{x + other.x, y + other.y};
}
- point operator-(const point &other) const {
+ auto operator-(const point &other) const -> point {
return point{x - other.x, y - other.y};
}
@@ -107,7 +107,7 @@ namespace stg {
constexpr rect(std::initializer_list l = {}) noexcept {
if (l.size() == 4) {
- auto it = l.begin();
+ const auto *it = l.begin();
left = *it++;
top = *it++;
width = *it++;
@@ -145,7 +145,7 @@ namespace stg {
}};
}
- point origin() {
+ auto origin() const -> point {
return point{left, top};
}
@@ -153,18 +153,18 @@ namespace stg {
return *this != rect::zero;
}
- friend bool operator==(const rect &lhs, const rect &rhs) {
+ friend auto operator==(const rect &lhs, const rect &rhs) -> bool {
return lhs.left == rhs.left &&
lhs.top == rhs.top &&
lhs.width == rhs.width &&
lhs.height == rhs.height;
}
- friend bool operator!=(const rect &lhs, const rect &rhs) {
+ friend auto operator!=(const rect &lhs, const rect &rhs) -> bool {
return !(lhs == rhs);
}
- friend std::ostream &operator<<(std::ostream &os, const rect &r) {
+ friend auto operator<<(std::ostream &os, const rect &r) -> std::ostream & {
os << "rect [ "
<< r.left << " "
<< r.top << " "
diff --git a/models/json.cpp b/models/json.cpp
index 1f53fec..db639aa 100644
--- a/models/json.cpp
+++ b/models/json.cpp
@@ -7,102 +7,103 @@
#include "json.h"
#include "strategy.h"
-std::string stg::json::serialize(const strategy &strategy) {
- auto json = nlohmann::json();
-
- json[keys::slot_duration] = strategy.time_slot_duration();
- json[keys::start_time] = strategy.begin_time();
-
- std::transform(strategy.activities().begin(),
- strategy.activities().end(),
- std::back_inserter(json[keys::activities]),
- [](auto activity) {
- return activity->to_json();
- });
-
- std::transform(strategy.time_slots().begin(),
- strategy.time_slots().end(),
- std::back_inserter(json[keys::slots]),
- [&strategy](auto &time_slot) {
- auto activity_index = strategy
- .activities()
- .index_of(time_slot.activity);
-
- if (activity_index) {
- return nlohmann::json(*activity_index);
- }
-
- return nlohmann::json();
- });
-
- return json.dump();
-}
-
-std::unique_ptr stg::json::parse(const std::string &json_string) {
- try {
- auto json = nlohmann::json::parse(json_string);
-
- auto activities = parse_activities(json);
- auto time_slots = parse_time_slots(json, activities);
-
- return std::make_unique(time_slots, activities);
- } catch (...) {
- return nullptr;
+namespace stg {
+ auto json::serialize(const strategy &strategy) -> std::string {
+ auto json = nlohmann::json();
+
+ json[keys::slot_duration] = strategy.time_slot_duration();
+ json[keys::start_time] = strategy.begin_time();
+
+ std::transform(strategy.activities().begin(),
+ strategy.activities().end(),
+ std::back_inserter(json[keys::activities]),
+ [](auto activity) {
+ return activity->to_json();
+ });
+
+ std::transform(strategy.time_slots().begin(),
+ strategy.time_slots().end(),
+ std::back_inserter(json[keys::slots]),
+ [&strategy](auto &time_slot) {
+ auto activity_index = strategy
+ .activities()
+ .index_of(time_slot.activity);
+
+ if (activity_index)
+ return nlohmann::json(*activity_index);
+
+ return nlohmann::json();
+ });
+
+ return json.dump();
}
-}
-stg::time_slots_state::data_t
-stg::json::parse_time_slots(const nlohmann::json &json,
- const activity_list::data_t &activities) {
- time_slots_state::data_t time_slots_vector;
+ auto json::parse(const std::string &json_string) -> std::unique_ptr {
+ try {
+ auto json = nlohmann::json::parse(json_string);
- auto time_slot_duration = strategy::defaults::time_slot_duration;
- if (!json[keys::slot_duration].is_null())
- time_slot_duration = json[keys::slot_duration];
+ auto activities = parse_activities(json);
+ auto time_slots = parse_time_slots(json, activities);
- auto begin_time = strategy::defaults::begin_time;
- if (!json[keys::start_time].is_null())
- begin_time = json[keys::start_time];
+ return std::make_unique(time_slots, activities);
+ } catch (...) {
+ return nullptr;
+ }
+ }
+
+ auto json::parse_time_slots(const nlohmann::json &json,
+ const activity_list::data_t &activities) -> time_slots_state::data_t {
+ time_slots_state::data_t time_slots_vector;
- if (!json[keys::slots].is_null()) {
- for (auto it = json[keys::slots].begin();
- it != json[keys::slots].end();
- ++it) {
+ auto time_slot_duration = strategy::defaults::time_slot_duration;
+ if (!json[keys::slot_duration].is_null())
+ time_slot_duration = json[keys::slot_duration];
- auto slot_index = it - json[keys::slots].begin();
- auto time_slot_begin_time = static_cast(begin_time + slot_index * time_slot_duration);
+ auto begin_time = strategy::defaults::begin_time;
+ if (!json[keys::start_time].is_null())
+ begin_time = json[keys::start_time];
- auto time_slot = stg::time_slot(time_slot_begin_time,
- time_slot_duration);
+ if (!json[keys::slots].is_null()) {
+ for (auto it = json[keys::slots].begin();
+ it != json[keys::slots].end();
+ ++it) {
- if (!it->is_null()) {
- auto activity_index = static_cast(*it);
+ auto slot_index = it - json[keys::slots].begin();
+ auto time_slot_begin_time = static_cast(begin_time +
+ slot_index * time_slot_duration);
- try {
- auto *activity = activities.at(activity_index).get();
- time_slot.activity = activity;
- } catch (const std::out_of_range &) {
- // activity is present in time slots, but not present in
- // strategy.activities(), so we won't preserve it.
+ auto time_slot = stg::time_slot(time_slot_begin_time,
+ time_slot_duration);
+
+ if (!it->is_null()) {
+ auto activity_index = static_cast(*it);
+
+ try {
+ auto *activity = activities.at(activity_index).get();
+ time_slot.activity = activity;
+ } catch (const std::out_of_range &) {
+ // activity is present in time slots, but not present in
+ // strategy.activities(), so we won't preserve it.
+ }
}
- }
- time_slots_vector.push_back(time_slot);
+ time_slots_vector.push_back(time_slot);
+ }
}
- }
- return time_slots_vector;
-}
+ return time_slots_vector;
+ }
-stg::activity_list::data_t stg::json::parse_activities(const nlohmann::json &json) {
- activity_list::data_t activities_vector;
+ auto json::parse_activities(const nlohmann::json &json) -> activity_list::data_t {
+ activity_list::data_t activities_vector;
- if (!json[keys::activities].is_null()) {
- for (const auto &activity_json : json[keys::activities]) {
- auto activity = std::make_shared(activity::from_json(activity_json));
- activities_vector.emplace_back(activity);
+ if (!json[keys::activities].is_null()) {
+ for (const auto &activity_json : json[keys::activities]) {
+ auto activity = std::make_shared(activity::from_json(activity_json));
+ activities_vector.emplace_back(activity);
+ }
}
- }
- return activities_vector;
-}
+ return activities_vector;
+ }
+}
\ No newline at end of file
diff --git a/models/json.h b/models/json.h
index 4bc2b39..aba151e 100644
--- a/models/json.h
+++ b/models/json.h
@@ -16,8 +16,8 @@ namespace stg {
class json {
public:
- static std::string serialize(const strategy &strategy);
- static std::unique_ptr parse(const std::string &json_string);
+ static auto serialize(const strategy &strategy) -> std::string;
+ static auto parse(const std::string &json_string) -> std::unique_ptr;
struct keys {
static constexpr auto slot_duration = "slotDuration";
@@ -28,12 +28,9 @@ namespace stg {
private:
activity_list activities;
- static activity_list::data_t
- parse_activities(const nlohmann::json &json);
-
- static time_slots_state::data_t
- parse_time_slots(const nlohmann::json &json,
- const activity_list::data_t &activities);
+ static auto parse_activities(const nlohmann::json &json) -> activity_list::data_t;
+ static auto parse_time_slots(const nlohmann::json &json,
+ const activity_list::data_t &activities) -> time_slots_state::data_t;
};
}
diff --git a/models/notifier.cpp b/models/notifier.cpp
index 6ada2a0..91c90af 100644
--- a/models/notifier.cpp
+++ b/models/notifier.cpp
@@ -11,235 +11,236 @@
#include "strategy.h"
#include "time_utils.h"
-stg::notifier::notifier(const stg::strategy &strategy) : strategy(strategy) {
- strategy.add_on_change_callback(this,
- &stg::notifier::schedule);
+namespace stg {
+ notifier::notifier(const stg::strategy &strategy) : strategy(strategy) {
+ strategy.add_on_change_callback(this,
+ &stg::notifier::schedule);
- schedule();
-}
+ schedule();
+ }
-void stg::notifier::start_watching() {
- is_watching = true;
+ void notifier::start_watching() {
+ is_watching = true;
- // schedule();
-}
+ // schedule();
+ }
-void stg::notifier::stop_watching() {
- is_watching = false;
+ void notifier::stop_watching() {
+ is_watching = false;
- // teardown();
-}
+ // teardown();
+ }
-void stg::notifier::schedule() {
+ void notifier::schedule() {
// std::cout << "scheduled notifications: \n";
- std::vector notifications;
- for (auto it = strategy.sessions().begin(); it != strategy.sessions().end(); ++it) {
- const auto &session = *it;
- auto next_it = std::next(it);
-
- if (session.activity) {
- notifications.emplace_back(session,
- notification::type::prepare_start);
- notifications.emplace_back(session,
- notification::type::start);
+ std::vector notifications;
+ for (auto it = strategy.sessions().begin(); it != strategy.sessions().end(); ++it) {
+ const auto &session = *it;
+ auto next_it = std::next(it);
- if (next_it != strategy.sessions().end() && !next_it->activity) {
+ if (session.activity) {
notifications.emplace_back(session,
- notification::type::prepare_end);
+ notification::type::prepare_start);
notifications.emplace_back(session,
- notification::type::end);
+ notification::type::start);
+
+ if (next_it != strategy.sessions().end() && !next_it->activity) {
+ notifications.emplace_back(session,
+ notification::type::prepare_end);
+ notifications.emplace_back(session,
+ notification::type::end);
+ }
}
- }
- if (next_it == strategy.sessions().end()) {
- notifications.emplace_back(session,
- notification::type::prepare_strategy_end);
- notifications.emplace_back(session,
- notification::type::strategy_end);
+ if (next_it == strategy.sessions().end()) {
+ notifications.emplace_back(session,
+ notification::type::prepare_strategy_end);
+ notifications.emplace_back(session,
+ notification::type::strategy_end);
+ }
}
- }
- remove_stale(notifications);
+ remove_stale(notifications);
// for (auto &n : notifications) {
// std::cout << n << "\n";
// }
- if (on_delete_notifications)
- on_delete_notifications(scheduled_identifiers());
+ if (on_delete_notifications)
+ on_delete_notifications(scheduled_identifiers());
- _scheduled_notifications = notifications;
+ _scheduled_notifications = notifications;
- if (on_schedule_notifications)
- on_schedule_notifications(_scheduled_notifications);
-}
+ if (on_schedule_notifications)
+ on_schedule_notifications(_scheduled_notifications);
+ }
-void stg::notifier::remove_stale(std::vector ¬ifications) {
- auto current_seconds = stg::time_utils::current_seconds();
- notifications.erase(std::remove_if(notifications.begin(),
- notifications.end(),
- [current_seconds](const stg::notification ¬ification) {
- return notification.delivery_time < current_seconds;
- }), notifications.end());
-}
+ void notifier::remove_stale(std::vector ¬ifications) {
+ auto current_seconds = stg::time_utils::current_seconds();
+ notifications.erase(std::remove_if(notifications.begin(),
+ notifications.end(),
+ [current_seconds](const stg::notification ¬ification) {
+ return notification.delivery_time < current_seconds;
+ }), notifications.end());
+ }
-std::string stg::notification::make_string_uuid() {
- auto uuid = boost::uuids::random_generator()();
+ auto notification::make_string_uuid() -> std::string {
+ auto uuid = boost::uuids::random_generator()();
- std::stringstream sstream;
- sstream << uuid;
+ std::stringstream sstream;
+ sstream << uuid;
- return sstream.str();
-}
+ return sstream.str();
+ }
-const std::vector
-&stg::notifier::scheduled_notifications() const {
- return _scheduled_notifications;
-}
+ auto notifier::scheduled_notifications() const -> const std::vector & {
+ return _scheduled_notifications;
+ }
-std::vector stg::notifier::scheduled_identifiers() const {
- std::vector result;
- std::transform(_scheduled_notifications.begin(),
- _scheduled_notifications.end(),
- std::back_inserter(result),
- [](const auto ¬ification) {
- return notification.identifier;
- });
+ auto notifier::scheduled_identifiers() const -> std::vector {
+ std::vector result;
+ std::transform(_scheduled_notifications.begin(),
+ _scheduled_notifications.end(),
+ std::back_inserter(result),
+ [](const auto ¬ification) {
+ return notification.identifier;
+ });
- return result;
-}
+ return result;
+ }
-stg::notifier::seconds stg::notifier::immediate_delivery_seconds(stg::notifier::minutes minutes_time) {
- return minutes_time * 60 - immediate_seconds_interval;
-}
+ auto notifier::immediate_delivery_seconds(minutes minutes_time) -> seconds {
+ return minutes_time * 60 - immediate_seconds_interval;
+ }
-stg::notifier::seconds stg::notifier::prepare_delivery_seconds(stg::notifier::minutes minutes_time) {
- return minutes_time * 60 - prepare_seconds_interval;
-}
+ auto notifier::prepare_delivery_seconds(minutes minutes_time) -> seconds {
+ return minutes_time * 60 - prepare_seconds_interval;
+ }
-void stg::notifier::send_now_if_needed(seconds polling_seconds_interval) {
+ void notifier::send_now_if_needed(seconds polling_seconds_interval) {
// std::cout << "send notification, if needed => \n";
- auto current_time = time_utils::current_seconds();
+ auto current_time = time_utils::current_seconds();
- if (last_poll_time && current_time - last_poll_time > 4 * polling_seconds_interval) {
+ if (last_poll_time && current_time - last_poll_time > 4 * polling_seconds_interval) {
// std::cout << "system time changed\n";
- // If time difference between two calls of this function was too big,
- // this probably means that the system time had changed, we need to reschedule.
- schedule();
- }
+ // If time difference between two calls of this function was too big,
+ // this probably means that the system time had changed, we need to reschedule.
+ schedule();
+ }
- last_poll_time = current_time;
+ last_poll_time = current_time;
- if (_scheduled_notifications.empty() ||
- current_time < _scheduled_notifications.front().delivery_time)
- return;
+ if (_scheduled_notifications.empty() ||
+ current_time < _scheduled_notifications.front().delivery_time)
+ return;
// std::cout << "current_time: " << current_time << "\n";
// std::cout << "delivery_time: " << next_notification.delivery_time << "\n";
- // We have to send only last notification for which delivery time is less than the current.
- // The first is guaranteed to be so, we need to check the others:
+ // We have to send only last notification for which delivery time is less than the current.
+ // The first is guaranteed to be so, we need to check the others:
- auto next_notification_it = _scheduled_notifications.begin();
- for (auto it = std::next(_scheduled_notifications.begin());
- it != _scheduled_notifications.end();
- ++it) {
- auto ¬ification = *it;
+ auto next_notification_it = _scheduled_notifications.begin();
+ for (auto it = std::next(_scheduled_notifications.begin());
+ it != _scheduled_notifications.end();
+ ++it) {
+ auto ¬ification = *it;
- if (current_time < notification.delivery_time) {
- next_notification_it = std::prev(it);
- break;
+ if (current_time < notification.delivery_time) {
+ next_notification_it = std::prev(it);
+ break;
+ }
}
- }
- auto &next_notification = *next_notification_it;
+ auto &next_notification = *next_notification_it;
- if (on_send_notiifcation)
- on_send_notiifcation(next_notification);
+ if (on_send_notiifcation)
+ on_send_notiifcation(next_notification);
// std::cout << "notification sent: " << next_notification << "\n";
- // Remove sent and stale notifications
- _scheduled_notifications.erase(_scheduled_notifications.begin(),
- std::next(next_notification_it));
-}
-
-std::string stg::notification::make_title(const session &session, type type) {
- if (type == type::prepare_strategy_end ||
- type == type::strategy_end) {
- return "End Of A Strategy";
- }
-
- if (!session.activity) {
- throw std::invalid_argument("session must have an activity for this type of notification");
- }
-
- return session.activity->name()
- + " ("
- + stg::time_utils::human_string_from_minutes(session.duration())
- + ")";
-}
-
-stg::notification::seconds stg::notification::make_delivery_time(const session &session, type type) {
- switch (type) {
- case type::prepare_start:
- return notifier::prepare_delivery_seconds(session.begin_time());
- case type::start:
- return notifier::immediate_delivery_seconds(session.begin_time());
- case type::prepare_end:
- case type::prepare_strategy_end:
- return notifier::prepare_delivery_seconds(session.end_time());
- case type::end:
- case type::strategy_end:
- return notifier::immediate_delivery_seconds(session.end_time());
- default:
- return 0;
- }
-}
-
-std::string stg::notification::make_sub_title(const session &session, type type) {
- switch (type) {
- case type::prepare_start:
- return "Coming up in "
- + time_utils::human_string_from_minutes(notifier::prepare_seconds_interval / 60);
- case type::start:
- return "Starts right now";
- case type::prepare_end:
- return "Ends in "
- + time_utils::human_string_from_minutes(notifier::prepare_seconds_interval / 60);
- case type::end:
- return "Ends right now";
- case type::prepare_strategy_end:
- return "Strategy ends in "
- + time_utils::human_string_from_minutes(notifier::prepare_seconds_interval / 60);
- case type::strategy_end:
- return "Strategy ends right now";
- default:
- return "";
- }
-}
-
-stg::notification::notification(const session &session, type type) :
- title(make_title(session, type)),
- message(make_sub_title(session, type)),
- delivery_time(make_delivery_time(session, type)) {}
-
-std::ostream &stg::operator<<(std::ostream &os, const stg::notification ¬ification) {
- os << "notification: [ ";
- os << "id: \"" << notification.identifier << "\", ";
- os << "title: \"" << notification.title << "\", ";
- os << "message: \"" << notification.message << "\", ";
- os << "delivery_time: \"" << time_utils::string_from_seconds(notification.delivery_time) << "\"";
- os << "]";
-
- return os;
-}
-
-bool stg::operator==(const stg::notification &lhs, const stg::notification &rhs) {
- // Two notifications are considered equal if all properties other than id are equal,
- return lhs.title == rhs.title &&
- lhs.message == rhs.message &&
- lhs.delivery_time == rhs.delivery_time;
-}
+ // Remove sent and stale notifications
+ _scheduled_notifications.erase(_scheduled_notifications.begin(),
+ std::next(next_notification_it));
+ }
+
+ auto notification::make_title(const session &session, type type) -> std::string {
+ if (type == type::prepare_strategy_end ||
+ type == type::strategy_end) {
+ return "End Of A Strategy";
+ }
+
+ if (!session.activity) {
+ throw std::invalid_argument("session must have an activity for this type of notification");
+ }
+
+ return session.activity->name()
+ + " ("
+ + time_utils::human_string_from_minutes(session.duration())
+ + ")";
+ }
+
+ auto notification::make_delivery_time(const session &session, type type) -> seconds {
+ switch (type) {
+ case type::prepare_start:
+ return notifier::prepare_delivery_seconds(session.begin_time());
+ case type::start:
+ return notifier::immediate_delivery_seconds(session.begin_time());
+ case type::prepare_end:
+ case type::prepare_strategy_end:
+ return notifier::prepare_delivery_seconds(session.end_time());
+ case type::end:
+ case type::strategy_end:
+ return notifier::immediate_delivery_seconds(session.end_time());
+ default:
+ return 0;
+ }
+ }
+
+ auto notification::make_sub_title(const session &session, type type) -> std::string {
+ switch (type) {
+ case type::prepare_start:
+ return "Coming up in "
+ + time_utils::human_string_from_minutes(notifier::prepare_seconds_interval / 60);
+ case type::start:
+ return "Starts right now";
+ case type::prepare_end:
+ return "Ends in "
+ + time_utils::human_string_from_minutes(notifier::prepare_seconds_interval / 60);
+ case type::end:
+ return "Ends right now";
+ case type::prepare_strategy_end:
+ return "Strategy ends in "
+ + time_utils::human_string_from_minutes(notifier::prepare_seconds_interval / 60);
+ case type::strategy_end:
+ return "Strategy ends right now";
+ default:
+ return "";
+ }
+ }
+
+ notification::notification(const session &session, type type) :
+ title(make_title(session, type)),
+ message(make_sub_title(session, type)),
+ delivery_time(make_delivery_time(session, type)) {}
+
+ auto operator<<(std::ostream &os, const notification ¬ification) -> std::ostream & {
+ os << "notification: [ ";
+ os << "id: \"" << notification.identifier << "\", ";
+ os << "title: \"" << notification.title << "\", ";
+ os << "message: \"" << notification.message << "\", ";
+ os << "delivery_time: \"" << time_utils::string_from_seconds(notification.delivery_time) << "\"";
+ os << "]";
+
+ return os;
+ }
+
+ auto operator==(const notification &lhs, const notification &rhs) -> bool {
+ // Two notifications are considered equal if all properties other than id are equal,
+ return lhs.title == rhs.title &&
+ lhs.message == rhs.message &&
+ lhs.delivery_time == rhs.delivery_time;
+ }
+}
\ No newline at end of file
diff --git a/models/notifier.h b/models/notifier.h
index cad47b7..814e0fa 100644
--- a/models/notifier.h
+++ b/models/notifier.h
@@ -36,10 +36,10 @@ namespace stg {
seconds delivery_time;
private:
- static std::string make_string_uuid();
- static std::string make_title(const session &session, type type);
- static std::string make_sub_title(const session &session, type type);
- static seconds make_delivery_time(const session &session, type type);
+ static auto make_string_uuid() -> std::string;
+ static auto make_title(const session &session, type type) -> std::string;
+ static auto make_sub_title(const session &session, type type) -> std::string;
+ static auto make_delivery_time(const session &session, type type) -> seconds;
friend bool operator==(const notification &lhs, const notification &rhs);
@@ -55,8 +55,8 @@ namespace stg {
using resetter_t = std::function &)>;
using sender_t = std::function;
- static seconds immediate_delivery_seconds(minutes minutes_time);
- static seconds prepare_delivery_seconds(minutes minutes_time);
+ static auto immediate_delivery_seconds(minutes minutes_time) -> seconds;
+ static auto prepare_delivery_seconds(minutes minutes_time) -> seconds;
scheduler_t on_schedule_notifications = nullptr;
resetter_t on_delete_notifications = nullptr;
@@ -70,8 +70,8 @@ namespace stg {
void send_now_if_needed(seconds polling_seconds_interval);
- const std::vector &scheduled_notifications() const;
- std::vector scheduled_identifiers() const;
+ auto scheduled_notifications() const -> const std::vector &;
+ auto scheduled_identifiers() const -> std::vector;
static const seconds prepare_seconds_interval = 5 * 60;
static const seconds immediate_seconds_interval = 20;
diff --git a/models/resizeoperation.cpp b/models/resizeoperation.cpp
index 41df332..ee81501 100644
--- a/models/resizeoperation.cpp
+++ b/models/resizeoperation.cpp
@@ -4,21 +4,20 @@
#include "resizeoperation.h"
-stg::resize_operation::resize_operation(time_slots_state *time_slots) :
- time_slots(time_slots) {
-}
+namespace stg {
+ resize_operation::resize_operation(time_slots_state *time_slots) :
+ time_slots(time_slots) {
+ }
-void stg::resize_operation::fill_slots(time_slots_state::index_t from_index,
- time_slots_state::index_t till_index) {
- time_slots->fill_slots(from_index, till_index);
-}
+ void resize_operation::fill_slots(index_t from_index, index_t till_index) {
+ time_slots->fill_slots(from_index, till_index);
+ }
-void stg::resize_operation::fill_slots_shifting(time_slots_state::index_t from_index,
- time_slots_state::index_t till_index) {
- time_slots->fill_slots_shifting(from_index, till_index);
-}
+ void resize_operation::fill_slots_shifting(index_t from_index, index_t till_index) {
+ time_slots->fill_slots_shifting(from_index, till_index);
+ }
-bool stg::resize_operation::state_changed() {
- return time_slots->data() != initial_time_slots;
+ auto resize_operation::state_changed() -> bool {
+ return time_slots->data() != initial_time_slots;
+ }
}
-
diff --git a/models/resizeoperation.h b/models/resizeoperation.h
index c8ef3e6..71124f8 100644
--- a/models/resizeoperation.h
+++ b/models/resizeoperation.h
@@ -10,15 +10,14 @@
namespace stg {
class resize_operation {
public:
- explicit resize_operation(time_slots_state *time_slots);
+ using index_t = time_slots_state::index_t;
- void fill_slots(time_slots_state::index_t from_index,
- time_slots_state::index_t till_index);
+ explicit resize_operation(time_slots_state *time_slots);
- void fill_slots_shifting(time_slots_state::index_t from_index,
- time_slots_state::index_t till_index);
+ void fill_slots(index_t from_index, index_t till_index);
+ void fill_slots_shifting(index_t from_index, index_t till_index);
- bool state_changed();
+ auto state_changed() -> bool;
private:
time_slots_state *time_slots;
time_slots_state::data_t initial_time_slots = time_slots->data();
diff --git a/models/selection.cpp b/models/selection.cpp
index f3f5d8e..9906c2f 100644
--- a/models/selection.cpp
+++ b/models/selection.cpp
@@ -100,7 +100,7 @@ bool stg::selection::only_non_empty_selected() const {
}) == end();
}
-bool stg::selection::has_selected(index_t slot_index) {
+bool stg::selection::has_selected(index_t slot_index) const {
return std::find(begin(), end(), slot_index) != end();
}
@@ -145,12 +145,17 @@ void stg::selection::on_change_event() {
reload();
}
-const stg::grouped_selection &stg::selection::grouped() {
+const stg::grouped_selection &stg::selection::grouped() const {
return _grouped;
}
-bool stg::selection::is_all_selected() {
+bool stg::selection::is_all_selected() const {
return size() == strategy.number_of_time_slots();
}
+bool stg::selection::is_boundary(stg::index_t slot_index) const {
+ return (!has_selected(slot_index - 1) && has_selected(slot_index))
+ || (has_selected(slot_index - 1) && !has_selected(slot_index));
+}
+
diff --git a/models/selection.h b/models/selection.h
index 9668d69..dd1506b 100644
--- a/models/selection.h
+++ b/models/selection.h
@@ -34,15 +34,17 @@ namespace stg {
bool only_empty_selected() const;
bool only_non_empty_selected() const;
- bool has_selected(index_t slot_index);
- bool is_all_selected();
+ bool has_selected(index_t slot_index) const;
+ bool is_all_selected() const;
+
+ bool is_boundary(index_t slot_index) const;
void reload();
bool is_clicked() const;
void set_is_clicked(bool is_clicked);
- const grouped_selection &grouped();
+ const grouped_selection &grouped() const;
void on_change_event() override;
private:
diff --git a/models/strategy.cpp b/models/strategy.cpp
index 3fb6f79..46715b9 100644
--- a/models/strategy.cpp
+++ b/models/strategy.cpp
@@ -7,484 +7,503 @@
#include "json.h"
#include "time_utils.h"
-stg::strategy::strategy(time_t begin_time, duration_t time_slot_duration,
- size_t number_of_time_slots)
- : _time_slots(time_slots_state(begin_time,
- time_slot_duration,
- number_of_time_slots)),
-
- history(make_history_entry()) {
- time_slots_changed();
- setup_time_slots_callback();
-}
-
-stg::strategy::strategy(const time_slots_state::data_t &time_slots,
- const activity_list::data_t &activities) :
- _time_slots(time_slots),
- _activities(activities),
- history(make_history_entry()) {
- time_slots_changed();
- setup_time_slots_callback();
-}
+namespace stg {
+ strategy::strategy(time_t begin_time, duration_t time_slot_duration,
+ size_t number_of_time_slots)
+ : _time_slots(time_slots_state(begin_time,
+ time_slot_duration,
+ number_of_time_slots)),
+
+ history(make_history_entry()) {
+ time_slots_changed();
+ setup_time_slots_callback();
+ }
-stg::strategy::strategy(const strategy &other) :
- _time_slots(other._time_slots.data()),
- _activities(other._activities.data()),
- _sessions(other.sessions().data()),
- history(make_history_entry()) {
+ strategy::strategy(const time_slots_state::data_t &time_slots,
+ const activity_list::data_t &activities) :
+ _time_slots(time_slots),
+ _activities(activities),
+ history(make_history_entry()) {
+ time_slots_changed();
+ setup_time_slots_callback();
+ }
- setup_time_slots_callback();
-}
+ strategy::strategy(const strategy &other) :
+ _time_slots(other._time_slots.data()),
+ _activities(other._activities.data()),
+ _sessions(other.sessions().data()),
+ history(make_history_entry()) {
+ setup_time_slots_callback();
+ }
-stg::strategy &stg::strategy::operator=(const strategy &other) {
- _time_slots.reset_with(other.time_slots().data());
- // Note: _time_slots on_change callback is private,
- // so we don't call on_change_event();
+ strategy &stg::strategy::operator=(const strategy &other) {
+ _time_slots.reset_with(other.time_slots().data());
+ // Note: _time_slots on_change callback is private,
+ // so we don't call on_change_event();
- _activities.reset_with(other.activities().data());
- _activities.on_change_event();
+ _activities.reset_with(other.activities().data());
+ _activities.on_change_event();
- _sessions.reset_with(other.sessions().data());
- _sessions.on_change_event();
+ _sessions.reset_with(other.sessions().data());
+ _sessions.on_change_event();
- history = strategy_history(make_history_entry());
+ history = strategy_history(make_history_entry());
- return *this;
-}
+ return *this;
+ }
-const stg::activity_list &stg::strategy::activities() const {
- return _activities;
-}
+ auto strategy::activities() const -> const activity_list & {
+ return _activities;
+ }
-void stg::strategy::silently_add_activity(const activity &activity) {
- _activities.silently_add(activity);
+ void strategy::silently_add_activity(const activity &activity) {
+ _activities.silently_add(activity);
- commit_to_history();
-}
+ commit_to_history();
+ }
-void stg::strategy::add_activity(const activity &activity) {
- _activities.add(activity);
+ void strategy::add_activity(const activity &activity) {
+ _activities.add(activity);
- commit_to_history();
-}
+ commit_to_history();
+ }
-void stg::strategy::delete_activity(activity_index activity_index) {
- _time_slots.remove_activity(_activities.at(activity_index));
- _activities.remove_at_index(activity_index);
+ void strategy::delete_activity(activity_index_t activity_index) {
+ _time_slots.remove_activity(_activities.at(activity_index));
+ _activities.remove_at_index(activity_index);
- commit_to_history();
-}
+ commit_to_history();
+ }
-void stg::strategy::silently_delete_activity(activity_index activity_index) {
- _time_slots.remove_activity(_activities.at(activity_index));
- _activities.silently_remove_at_index(activity_index);
+ void strategy::silently_delete_activity(activity_index_t activity_index) {
+ _time_slots.remove_activity(_activities.at(activity_index));
+ _activities.silently_remove_at_index(activity_index);
- commit_to_history();
-}
+ commit_to_history();
+ }
-void stg::strategy::silently_edit_activity(activity_index activity_index,
- const activity &new_activity) {
- const auto old_activity = _activities.at(activity_index);
- _activities.silently_edit_at_index(activity_index, new_activity);
+ void strategy::silently_edit_activity(activity_index_t activity_index,
+ const activity &new_activity) {
+ const auto old_activity = _activities.at(activity_index);
+ _activities.silently_edit_at_index(activity_index, new_activity);
- const auto updated_activity = _activities.at(activity_index);
- _time_slots.edit_activity(old_activity, updated_activity);
+ const auto updated_activity = _activities.at(activity_index);
+ _time_slots.edit_activity(old_activity, updated_activity);
- commit_to_history();
-}
+ commit_to_history();
+ }
-void stg::strategy::edit_activity(activity_index activity_index,
- const activity &new_activity) {
- const auto old_activity = _activities.at(activity_index);
- _activities.edit_at_index(activity_index, new_activity);
+ void strategy::edit_activity(activity_index_t activity_index,
+ const activity &new_activity) {
+ auto *old_activity = _activities.at(activity_index);
+ _activities.edit_at_index(activity_index, new_activity);
- const auto updated_activity = _activities.at(activity_index);
- _time_slots.edit_activity(old_activity, updated_activity);
+ auto *updated_activity = _activities.at(activity_index);
+ _time_slots.edit_activity(old_activity, updated_activity);
- commit_to_history();
-}
+ commit_to_history();
+ }
-stg::strategy::time_t stg::strategy::begin_time() const {
- return _time_slots.begin_time();
-}
+ stg::strategy::time_t stg::strategy::begin_time() const {
+ return _time_slots.begin_time();
+ }
-void stg::strategy::set_begin_time(time_t begin_time) {
- _time_slots.set_begin_time(begin_time);
+ void strategy::set_begin_time(time_t begin_time) {
+ _time_slots.set_begin_time(begin_time);
- commit_to_history();
-}
+ commit_to_history();
+ }
-stg::strategy::duration_t stg::strategy::time_slot_duration() const {
- return _time_slots.slot_duration();
-}
+ auto strategy::time_slot_duration() const -> duration_t {
+ return _time_slots.slot_duration();
+ }
-void stg::strategy::set_time_slot_duration(duration_t time_slot_duration) {
- _time_slots.set_slot_duration(time_slot_duration);
+ void strategy::set_time_slot_duration(duration_t time_slot_duration) {
+ _time_slots.set_slot_duration(time_slot_duration);
- commit_to_history();
-}
+ commit_to_history();
+ }
-stg::strategy::size_t stg::strategy::number_of_time_slots() const {
- return _time_slots.number_of_slots();
-}
+ auto strategy::number_of_time_slots() const -> size_t {
+ return _time_slots.number_of_slots();
+ }
-void stg::strategy::set_number_of_time_slots(size_t number_of_time_slots) {
- _time_slots.set_number_of_slots(number_of_time_slots);
+ void strategy::set_number_of_time_slots(size_t number_of_time_slots) {
+ _time_slots.set_number_of_slots(number_of_time_slots);
- commit_to_history();
-}
+ commit_to_history();
+ }
-void stg::strategy::time_slots_changed() {
- _sessions.recalculate(_time_slots);
-}
+ void strategy::set_end_time(time_t end_time) {
+ _time_slots.set_end_time(end_time);
-void stg::strategy::place_activity(activity_index activity_index,
- const std::vector &time_slot_indices) {
- if (!activities().has_index(activity_index)) {
- return;
+ commit_to_history();
}
- auto activity = activities().at(activity_index);
- _time_slots.set_activity_at_indices(activity, time_slot_indices);
+ void strategy::time_slots_changed() {
+ _sessions.recalculate(_time_slots);
+ }
- commit_to_history();
-}
+ void strategy::place_activity(activity_index_t activity_index,
+ const std::vector &time_slot_indices) {
+ if (!activities().has_index(activity_index)) {
+ return;
+ }
-void stg::strategy::make_empty_at(const std::vector &time_slot_indices) {
- _time_slots.set_activity_at_indices(stg::strategy::no_activity, time_slot_indices);
+ auto activity = activities().at(activity_index);
+ _time_slots.set_activity_at_indices(activity, time_slot_indices);
- commit_to_history();
-}
+ commit_to_history();
+ }
-void stg::strategy::drag_activity(activity_index from_index, activity_index to_index) {
- _activities.drag(from_index, to_index);
+ void strategy::make_empty_at(const std::vector &time_slot_indices) {
+ _time_slots.set_activity_at_indices(stg::strategy::no_activity,
+ time_slot_indices);
- commit_to_history();
-}
+ commit_to_history();
+ }
+ void strategy::drag_activity(activity_index_t from_index, activity_index_t to_index) {
+ _activities.drag(from_index, to_index);
-void stg::strategy::silently_drag_activity(stg::activity_index from_index, stg::activity_index to_index) {
- _activities.silently_drag(from_index, to_index);
+ commit_to_history();
+ }
- commit_to_history();
-}
-void stg::strategy::fill_time_slots_shifting(time_slot_index_t from_index, time_slot_index_t till_index) {
- assert(current_resize_operation && "fill_time_slots must be called between "
- "begin_resizing() and end_resizing() calls");
+ void strategy::silently_drag_activity(stg::activity_index_t from_index,
+ stg::activity_index_t to_index) {
+ _activities.silently_drag(from_index, to_index);
- current_resize_operation->fill_slots_shifting(from_index, till_index);
-}
+ commit_to_history();
+ }
-void stg::strategy::fill_time_slots(time_slot_index_t from_index, time_slot_index_t till_index) {
- assert(current_resize_operation && "fill_time_slots must be called between "
- "begin_resizing() and end_resizing() calls");
+ void strategy::fill_time_slots_shifting(time_slot_index_t from_index,
+ time_slot_index_t till_index) {
+ assert(current_resize_operation && "fill_time_slots must be called between "
+ "begin_resizing() and end_resizing() calls");
- current_resize_operation->fill_slots(from_index, till_index);
-}
+ current_resize_operation->fill_slots_shifting(from_index, till_index);
+ }
-const stg::sessions_list &stg::strategy::sessions() const {
- return _sessions;
-}
+ void strategy::fill_time_slots(time_slot_index_t from_index,
+ time_slot_index_t till_index) {
+ assert(current_resize_operation && "fill_time_slots must be called between "
+ "begin_resizing() and end_resizing() calls");
-stg::strategy::time_t stg::strategy::end_time() const {
- return _time_slots.last().end_time();
-}
+ current_resize_operation->fill_slots(from_index, till_index);
+ }
-void stg::strategy::setup_time_slots_callback() {
- _time_slots.add_on_change_callback(this, &stg::strategy::time_slots_changed);
-}
+ auto strategy::sessions() const -> const sessions_list & {
+ return _sessions;
+ }
-stg::strategy_history::entry stg::strategy::make_history_entry() {
- return strategy_history::entry{_activities.data(),
- _time_slots.data()};
-}
+ auto strategy::end_time() const -> time_t {
+ return _time_slots.end_time();
+ }
-void stg::strategy::commit_to_history() {
- if (history.commit(make_history_entry()))
- on_change_event();
-}
+ void strategy::setup_time_slots_callback() {
+ _time_slots.add_on_change_callback(this,
+ &strategy::time_slots_changed);
+ }
-void stg::strategy::undo() {
- auto history_entry = history.undo();
- if (history_entry) {
- apply_history_entry(history_entry);
+ auto strategy::make_history_entry() -> strategy_history::entry {
+ return strategy_history::entry{_activities.data(),
+ _time_slots.data()};
+ }
- on_change_event();
+ void strategy::commit_to_history() {
+ if (history.commit(make_history_entry()))
+ on_change_event();
}
-}
-void stg::strategy::redo() {
- auto history_entry = history.redo();
- if (history_entry) {
- apply_history_entry(history_entry);
+ void strategy::undo() {
+ auto history_entry = history.undo();
+ if (history_entry) {
+ apply_history_entry(history_entry);
- on_change_event();
+ on_change_event();
+ }
}
-}
-void stg::strategy::apply_history_entry(const std::optional &history_entry) {
- _activities.reset_with(history_entry->activities);
- _activities.on_change_event();
+ void strategy::redo() {
+ auto history_entry = history.redo();
+ if (history_entry) {
+ apply_history_entry(history_entry);
- _time_slots.reset_with(history_entry->time_slots);
- _time_slots.on_change_event();
-}
+ on_change_event();
+ }
+ }
-const stg::time_slots_state &stg::strategy::time_slots() const {
- return _time_slots;
-}
+ void strategy::apply_history_entry(const std::optional &history_entry) {
+ _activities.reset_with(history_entry->activities);
+ _activities.on_change_event();
-void stg::strategy::shift_below_time_slot(stg::strategy::time_slot_index_t from_index, int length) {
- _time_slots.shift_below(from_index, length);
+ _time_slots.reset_with(history_entry->time_slots);
+ _time_slots.on_change_event();
+ }
- commit_to_history();
-}
+ auto strategy::time_slots() const -> const time_slots_state & {
+ return _time_slots;
+ }
-stg::sessions_list::index_t
-stg::strategy::drag_session(stg::strategy::session_index_t session_index,
- int distance) {
- assert(current_drag_operation && "drag_session must be called between "
- "begin_dragging() and end_dragging() calls");
+ void strategy::shift_below_time_slot(time_slot_index_t from_index, int length) {
+ _time_slots.shift_below(from_index, length);
- if (session_index < 0 ||
- session_index > sessions().size() - 1 ||
- distance == 0) {
- return session_index;
+ commit_to_history();
}
- const auto &session = sessions()[session_index];
- if (session.activity == stg::strategy::no_activity) {
- return session_index;
- }
+ auto strategy::drag_session(session_index_t session_index,
+ int distance) -> sessions_list::index_t {
+ assert(current_drag_operation && "drag_session must be called between "
+ "begin_dragging() and end_dragging() calls");
- auto new_indexes = current_drag_operation->record_drag(session.time_slots, distance);
+ if (session_index < 0 ||
+ session_index > sessions().size() - 1 ||
+ distance == 0) {
+ return session_index;
+ }
- time_slots_changed();
+ const auto &session = sessions()[session_index];
+ if (session.activity == stg::strategy::no_activity) {
+ return session_index;
+ }
- auto new_session_index = new_indexes.empty()
- ? session_index
- : sessions().session_index_for_time_slot_index(new_indexes.front());
+ auto new_indexes = current_drag_operation->record_drag(session.time_slots, distance);
- return new_session_index;
-}
+ time_slots_changed();
-void stg::strategy::begin_dragging(session_index_t session_index) {
- auto &session = sessions()[session_index];
- auto initial_indices = global_slot_indices_from_session(session);
+ auto new_session_index = new_indexes.empty()
+ ? session_index
+ : sessions().session_index_for_time_slot_index(new_indexes.front());
- current_drag_operation = std::make_shared(&_time_slots, initial_indices);
-}
+ return new_session_index;
+ }
-std::vector
-stg::strategy::global_slot_indices_from_session(const session &session) const {
- drag_operation::indices_vector initial_indices;
- std::transform(session.time_slots.begin(),
- session.time_slots.end(),
- std::back_inserter(initial_indices),
- [this](auto &slot) -> time_slots_state::index_t {
- return *_time_slots.index_of(slot);
- });
-
- return initial_indices;
-}
+ void stg::strategy::begin_dragging(session_index_t session_index) {
+ const auto &session = sessions()[session_index];
+ auto initial_indices = global_slot_indices_from_session(session);
-void stg::strategy::end_dragging() {
- if (!current_drag_operation) {
- return;
+ current_drag_operation = std::make_shared(&_time_slots, initial_indices);
}
- if (current_drag_operation->state_changed()) {
- commit_to_history();
+ auto strategy::global_slot_indices_from_session(const session &session) const
+ -> std::vector {
+ drag_operation::indices_vector initial_indices;
+ std::transform(session.time_slots.begin(),
+ session.time_slots.end(),
+ std::back_inserter(initial_indices),
+ [this](auto &slot) -> time_slots_state::index_t {
+ return *_time_slots.index_of(slot);
+ });
+
+ return initial_indices;
}
- current_drag_operation.reset();
-}
+ void strategy::end_dragging() {
+ if (!current_drag_operation) {
+ return;
+ }
-void stg::strategy::cancel_dragging() {
- _time_slots.reset_with(current_drag_operation->initial_state());
- current_drag_operation.reset();
+ if (current_drag_operation->state_changed()) {
+ commit_to_history();
+ }
- time_slots_changed();
-}
+ current_drag_operation.reset();
+ }
-void stg::strategy::begin_resizing() {
- current_resize_operation = std::make_shared(&_time_slots);
-}
+ void strategy::cancel_dragging() {
+ _time_slots.reset_with(current_drag_operation->initial_state());
+ current_drag_operation.reset();
-void stg::strategy::end_resizing() {
- if (!current_resize_operation) {
- return;
+ time_slots_changed();
}
- if (current_resize_operation->state_changed()) {
- commit_to_history();
+ void strategy::begin_resizing() {
+ current_resize_operation = std::make_shared(&_time_slots);
}
- current_resize_operation.reset();
-}
+ void strategy::end_resizing() {
+ if (!current_resize_operation) {
+ return;
+ }
+
+ if (current_resize_operation->state_changed()) {
+ commit_to_history();
+ }
-void stg::strategy::copy_session(stg::strategy::session_index_t session_index,
- stg::strategy::time_slot_index_t begin_index) {
- auto &session = sessions()[session_index];
- if (!session.activity) {
- return;
+ current_resize_operation.reset();
}
- auto copied_session_indices = std::vector(session.length());
- std::iota(copied_session_indices.begin(),
- copied_session_indices.end(),
- begin_index);
+ void strategy::copy_session(session_index_t session_index,
+ time_slot_index_t begin_index) {
+ const auto &session = sessions()[session_index];
+ if (!session.activity) {
+ return;
+ }
- _time_slots.set_activity_at_indices(session.activity, copied_session_indices);
+ auto copied_session_indices = std::vector(session.length());
+ std::iota(copied_session_indices.begin(),
+ copied_session_indices.end(),
+ begin_index);
- commit_to_history();
-}
+ _time_slots.set_activity_at_indices(session.activity, copied_session_indices);
-stg::strategy::duration_t stg::strategy::duration() const {
- if (time_slots().empty()) {
- return duration_t();
+ commit_to_history();
}
- return time_slots().last().end_time() - time_slots().first().begin_time;
-}
-
-std::string stg::strategy::to_json_string() const {
- return json::serialize(*this);
-}
-
-std::unique_ptr stg::strategy::from_json_string(const std::string &json_string) {
- return json::parse(json_string);
-}
+ auto strategy::duration() const -> duration_t {
+ if (time_slots().empty()) {
+ return duration_t();
+ }
-const stg::session *stg::strategy::get_current_session() const {
- auto it = std::find_if(sessions().begin(),
- sessions().end(),
- [](const session &session) {
- return session.is_current();
- });
-
- if (it != sessions().end()) {
- return &*it;
+ return time_slots().last().end_time() - time_slots().first().begin_time;
}
- return nullptr;
-}
+ auto strategy::to_json_string() const -> std::string {
+ return json::serialize(*this);
+ }
-const stg::session *stg::strategy::active_session() const {
- auto current_session = this->get_current_session();
- if (!current_session || !current_session->activity) {
- return nullptr;
+ auto strategy::from_json_string(const std::string &json_string) -> std::unique_ptr {
+ return json::parse(json_string);
}
- return current_session;
-}
+ auto strategy::get_current_session() const -> const session * {
+ auto it = std::find_if(sessions().begin(),
+ sessions().end(),
+ [](const session &session) {
+ return session.is_current();
+ });
-const stg::session *stg::strategy::upcoming_session() const {
- auto current_session = this->get_current_session();
+ if (it != sessions().end()) {
+ return &*it;
+ }
- if (!current_session) {
- // we're out of strategy's time bounds.
return nullptr;
}
- const auto next_session = sessions().session_after(*current_session);
- return next_session && next_session->activity
- ? next_session
- : nullptr;
-}
+ auto strategy::active_session() const -> const session * {
+ const auto *current_session = this->get_current_session();
+ if (!current_session || !current_session->activity) {
+ return nullptr;
+ }
-void stg::strategy::reorder_activities_by_usage() {
- std::map usage;
+ return current_session;
+ }
- for (auto &session : sessions()) {
- if (session.activity == no_activity)
- continue;
+ auto strategy::upcoming_session() const -> const session * {
+ const auto *current_session = this->get_current_session();
- usage[session.activity] += session.duration();
- }
+ if (!current_session) {
+ // we're out of strategy's time bounds.
+ return nullptr;
+ }
- std::vector> pairs;
- for (const auto &elem : usage) {
- pairs.emplace_back(elem);
+ const auto *next_session = sessions().session_after(*current_session);
+ return next_session && next_session->activity
+ ? next_session
+ : nullptr;
}
- std::sort(pairs.begin(),
- pairs.end(),
- [=](auto &a, auto &b) {
- return a.second > b.second;
- });
+ void strategy::reorder_activities_by_usage() {
+ std::map usage;
- std::vector> reordered;
- for (auto &elem : pairs) {
- if (!elem.first)
- continue;
+ for (const auto &session : sessions()) {
+ if (session.activity == no_activity)
+ continue;
- auto index = *activities().index_of(elem.first);
- auto activity = _activities._data[index];
+ usage[session.activity] += session.duration();
+ }
- reordered.push_back(activity);
- }
+ std::vector> pairs;
+ for (const auto &elem : usage) {
+ pairs.emplace_back(elem);
+ }
+
+ std::sort(pairs.begin(),
+ pairs.end(),
+ [=](auto &a, auto &b) {
+ return a.second > b.second;
+ });
- for (auto &activity : _activities) {
- if (std::find_if(reordered.begin(),
- reordered.end(),
- [activity](auto a) {
- return a == activity;
- }) == reordered.end()) {
+ std::vector> reordered;
+ for (auto &elem : pairs) {
+ if (!elem.first)
+ continue;
+
+ auto index = *activities().index_of(elem.first);
+ auto activity = _activities._data[index];
reordered.push_back(activity);
- };
+ }
+
+ for (const auto &activity : _activities) {
+ if (std::find_if(reordered.begin(),
+ reordered.end(),
+ [activity](auto a) {
+ return a == activity;
+ }) == reordered.end()) {
+
+ reordered.push_back(activity);
+ };
+ }
+
+ if (_activities.data() != reordered) {
+ _activities.reset_with(reordered);
+ _activities.on_change_event();
+
+ commit_to_history();
+ }
}
- if (_activities.data() != reordered) {
- _activities.reset_with(reordered);
- _activities.on_change_event();
+ auto strategy::is_dragging() -> bool {
+ return current_drag_operation != nullptr;
+ }
- commit_to_history();
+ auto strategy::is_resizing() -> bool {
+ return current_resize_operation != nullptr;
}
-}
-bool stg::strategy::is_dragging() {
- return current_drag_operation != nullptr;
-}
+ auto strategy::from_file(const std::string &path) -> std::unique_ptr {
+ std::ifstream file(path);
-bool stg::strategy::is_resizing() {
- return current_resize_operation != nullptr;
-}
+ if (file.is_open()) {
+ std::stringstream buffer;
+ buffer << file.rdbuf();
+ auto json_string = buffer.str();
+
+ file.close();
-std::unique_ptr stg::strategy::from_file(const std::string &path) {
- std::ifstream file(path);
+ return from_json_string(json_string);
+ } else {
+ throw file_read_exception();
+ }
+ }
- if (file.is_open()) {
- std::stringstream buffer;
- buffer << file.rdbuf();
- auto json_string = buffer.str();
+ void strategy::write_to_file(const std::string &path) const {
+ auto file = std::ofstream(path);
- file.close();
+ if (file.is_open()) {
+ file << to_json_string();
+ file.close();
+ } else {
+ throw file_write_exception();
+ }
+ }
- return from_json_string(json_string);
- } else {
- throw file_read_exception();
+ auto strategy::has_activities_undo() -> bool {
+ return history.has_prevoius_activities_state();
}
-}
-void stg::strategy::write_to_file(const std::string &path) const {
- auto file = std::ofstream(path);
+ auto strategy::has_activities_redo() -> bool {
+ return history.has_next_activities_state();
+ }
- if (file.is_open()) {
- file << to_json_string();
- file.close();
- } else {
- throw file_write_exception();
+ auto strategy::has_undo() -> bool {
+ return history.has_prevoius_state();
}
-}
-bool stg::strategy::has_activities_undo() {
- return history.has_prevoius_activities_state();
-}
+ auto strategy::has_redo() -> bool {
+ return history.has_next_state();
+ }
-bool stg::strategy::has_activities_redo() {
- return history.has_next_activities_state();
}
-
diff --git a/models/strategy.h b/models/strategy.h
index 2488236..a90d456 100644
--- a/models/strategy.h
+++ b/models/strategy.h
@@ -40,77 +40,81 @@ namespace stg {
#pragma mark - Constructors & Operators
- explicit strategy(time_t begin_time_t = defaults::begin_time,
- duration_t time_slot_duration_t = defaults::time_slot_duration,
- size_t number_of_time_slots = defaults::number_of_time_slots);
-
+ explicit strategy(time_t
+ begin_time_t = defaults::begin_time,
+ duration_t
+ time_slot_duration_t = defaults::time_slot_duration,
+ size_t
+ number_of_time_slots = defaults::number_of_time_slots
+ );
strategy(const time_slots_state::data_t &time_slots,
const activity_list::data_t &activities);
-
strategy(const strategy &other);
- strategy &operator=(const strategy &other);
+ auto operator=(const strategy &other) -> strategy &;
#pragma mark - Import & Export
- static std::unique_ptr from_json_string(const std::string &json_string);
- std::string to_json_string() const;
+ static auto from_json_string(const std::string &json_string) -> std::unique_ptr;
+ auto to_json_string() const -> std::string;
- static std::unique_ptr from_file(const std::string &path) noexcept(false);
+ static auto from_file(const std::string &path) noexcept(false) -> std::unique_ptr;
void write_to_file(const std::string &path) const noexcept(false);
#pragma mark - Collections
- const activity_list &activities() const;
- const sessions_list &sessions() const;
- const time_slots_state &time_slots() const;
+ auto activities() const -> const activity_list &;
+ auto sessions() const -> const sessions_list &;
+ auto time_slots() const -> const time_slots_state &;
#pragma mark - Time Grid Properties
- time_t begin_time() const;
+ auto begin_time() const -> time_t;
void set_begin_time(time_t begin_time);
- duration_t time_slot_duration() const;
+ auto time_slot_duration() const -> duration_t;
void set_time_slot_duration(duration_t time_slot_duration);
- size_t number_of_time_slots() const;
+ auto number_of_time_slots() const -> size_t;
void set_number_of_time_slots(size_t number_of_time_slots);
- time_t end_time() const;
- duration_t duration() const;
+ auto end_time() const -> time_t;
+ void set_end_time(time_t end_time);
+
+ auto duration() const -> duration_t;
-#pragma mark - Real-time Properties
+#pragma mark - Real-Time Properties
- const session *active_session() const;
- const session *upcoming_session() const;
+ auto active_session() const -> const session *;
+ auto upcoming_session() const -> const session *;
#pragma mark - Operations On Activities
void add_activity(const activity &activity) noexcept(false);
void silently_add_activity(const activity &activity) noexcept(false);
- void delete_activity(activity_index activity_index);
- void silently_delete_activity(activity_index activity_index);
- void edit_activity(activity_index activity_index, const activity &new_activity) noexcept(false);
- void silently_edit_activity(activity_index activity_index, const activity &new_activity) noexcept(false);
- void drag_activity(activity_index from_index, activity_index to_index);
- void silently_drag_activity(activity_index from_index, activity_index to_index);
+ void delete_activity(activity_index_t activity_index);
+ void silently_delete_activity(activity_index_t activity_index);
+ void edit_activity(activity_index_t activity_index, const activity &new_activity) noexcept(false);
+ void silently_edit_activity(activity_index_t activity_index, const activity &new_activity) noexcept(false);
+ void drag_activity(activity_index_t from_index, activity_index_t to_index);
+ void silently_drag_activity(activity_index_t from_index, activity_index_t to_index);
void reorder_activities_by_usage();
#pragma mark - Operations On Slots
- void place_activity(activity_index activity_index, const std::vector &time_slot_indices);
+ void place_activity(activity_index_t activity_index, const std::vector &time_slot_indices);
void make_empty_at(const std::vector &time_slot_indices);
void shift_below_time_slot(time_slot_index_t from_index, int length);
- bool is_resizing();
+ auto is_resizing() -> bool;
void begin_resizing();
void fill_time_slots_shifting(time_slot_index_t from_index, time_slot_index_t till_index);
void fill_time_slots(time_slot_index_t from_index, time_slot_index_t till_index);
void end_resizing();
- bool is_dragging();
+ auto is_dragging() -> bool;
void begin_dragging(session_index_t session_index);
- stg::sessions_list::index_t drag_session(session_index_t session_index, int distance);
+ auto drag_session(session_index_t session_index, int distance) -> sessions_list::index_t;
void end_dragging();
void cancel_dragging();
@@ -121,8 +125,12 @@ namespace stg {
void commit_to_history();
void undo();
void redo();
- bool has_activities_undo();
- bool has_activities_redo();
+
+ auto has_undo() -> bool;
+ auto has_redo() -> bool;
+
+ auto has_activities_undo() -> bool;
+ auto has_activities_redo() -> bool;
private:
activity_list _activities;
time_slots_state _time_slots;
@@ -136,13 +144,12 @@ namespace stg {
void setup_time_slots_callback();
// current session, may be empty
- const session *get_current_session() const;
+ auto get_current_session() const -> const session *;
- strategy_history::entry make_history_entry();
+ auto make_history_entry() -> strategy_history::entry;
void apply_history_entry(const std::optional &history_entry);
- std::vector
- global_slot_indices_from_session(const session &session) const;
+ auto global_slot_indices_from_session(const session &session) const -> std::vector;
};
}
diff --git a/models/tests/activity_tests.cpp b/models/tests/activity_tests.cpp
index bd5177e..a542b24 100644
--- a/models/tests/activity_tests.cpp
+++ b/models/tests/activity_tests.cpp
@@ -40,13 +40,13 @@ TEST_CASE("stg::activity immutability", "[activity]") {
const auto activity = stg::activity(intial_name);
SECTION("copy changing name") {
- REQUIRE(activity.copy_changing_name("Some 2")
+ REQUIRE(activity.with_name("Some 2")
== stg::activity("Some 2"));
REQUIRE(activity == stg::activity(intial_name));
}
SECTION("copy changing color") {
- REQUIRE(activity.copy_changing_color(RED_COLOR)
+ REQUIRE(activity.with_color(RED_COLOR)
== stg::activity(intial_name, RED_COLOR));
REQUIRE(activity == stg::activity(intial_name));
}
diff --git a/models/theme.cpp b/models/theme.cpp
new file mode 100644
index 0000000..71ae77c
--- /dev/null
+++ b/models/theme.cpp
@@ -0,0 +1,87 @@
+//
+// Created by Dmitry Khrykin on 26/04/2020.
+//
+
+#include "theme.h"
+
+namespace stg {
+
+ auto theme::text_color() const -> color {
+ return get_text_color();
+ }
+
+ auto theme::base_color() const -> color {
+ return get_base_color();
+ }
+
+ auto theme::session_background_color(const session &session, bool is_selected) const -> color {
+ if (!session.activity)
+ return color::clear_color();
+
+ auto activity_color = session.activity->color();
+
+ if (activity_color.lightness() < 0.5 &&
+ is_dark_mode()) {
+ activity_color.set_hsl(activity_color.hue(), activity_color.saturation(), 0.2);
+ }
+
+ return is_selected
+ ? activity_color
+ : activity_color.with_alpha_component(0.15);
+ }
+
+ auto theme::session_ruler_color(const session &session, bool is_selected) const -> color {
+ return is_selected
+ ? session.activity->desaturated_dark_color()
+ : session.activity->desaturated_light_color();
+ }
+
+ auto theme::session_duration_color(const session &session, bool is_selected) const -> color {
+ if (!session.activity)
+ return color::clear_color();
+
+ const auto activity_color = session.activity->color();
+ auto default_duration_color = text_color()
+ .blended_with(activity_color
+ .with_hsl(activity_color.hue(), 0.2, 0.7)
+ .with_alpha_component(0.6));
+
+ auto selected_duration_color = base_color()
+ .blended_with(activity_color
+
+ .with_alpha_component(0.2));
+
+ auto duration_color = is_selected
+ ? selected_duration_color
+ : default_duration_color;
+
+
+ if (session.activity->color().lightness() < 0.2 && is_selected) {
+ duration_color = color::white_color()
+ .blended_with(session.activity->color().with_alpha_component(0.5));
+ }
+
+ return duration_color;
+ }
+
+ auto theme::session_title_color(const session &session, bool is_selected) const -> color {
+ auto activity_color = session.activity->color();
+ auto lightened_activity_color = activity_color.with_hsl(activity_color.hue(),
+ activity_color.saturation(),
+ 1 - activity_color.lightness());
+
+ if (is_selected) {
+ return color::white_color();
+ } else {
+ if (activity_color.lightness() < 0.5 && is_dark_mode())
+ return lightened_activity_color;
+
+ return session.activity->color();
+ }
+ }
+
+ auto theme::is_dark_mode() const -> bool {
+ return text_color().lightness() > 0.2;
+ }
+
+}
diff --git a/models/theme.h b/models/theme.h
new file mode 100644
index 0000000..38a15e3
--- /dev/null
+++ b/models/theme.h
@@ -0,0 +1,33 @@
+//
+// Created by Dmitry Khrykin on 26/04/2020.
+//
+
+#ifndef STRATEGR_THEME_H
+#define STRATEGR_THEME_H
+
+#include
+#include
+
+#include "color.h"
+#include "session.h"
+#include "activity.h"
+
+namespace stg {
+ struct theme {
+ std::function get_text_color = [] {
+ return color::black_color();
+ };
+ std::function get_base_color = [] { return color::white_color(); };
+
+ auto text_color() const -> color;
+ auto base_color() const -> color;
+ auto is_dark_mode() const -> bool;
+
+ auto session_background_color(const session &session, bool is_selected) const -> color;
+ auto session_ruler_color(const session &session, bool is_selected) const -> color;
+ auto session_duration_color(const session &session, bool is_selected) const -> color;
+ auto session_title_color(const session &session, bool is_selected) const -> color;
+ };
+}
+
+#endif //STRATEGR_THEME_H
diff --git a/models/time_utils.cpp b/models/time_utils.cpp
index d623ed5..b23d602 100644
--- a/models/time_utils.cpp
+++ b/models/time_utils.cpp
@@ -6,88 +6,87 @@
#include "time_utils.h"
namespace stg {
-time_utils::minutes time_utils::current_minutes() {
- return current_seconds() / 60;
-}
-
-time_utils::seconds time_utils::current_seconds() {
- auto duration = current_day_duration();
- return static_cast(std::chrono::duration_cast(duration).count());
-}
+ auto time_utils::current_minutes() -> time_utils::minutes {
+ return current_seconds() / 60;
+ }
-time_utils::timestamp
-time_utils::start_of_a_day_from_timestamp(time_utils::timestamp timestamp) {
- auto day_components = *day_components_from_timestamp(×tamp);
+ auto time_utils::current_seconds() -> time_utils::seconds {
+ auto duration = current_day_duration();
+ return static_cast(std::chrono::duration_cast(duration).count());
+ }
- day_components.tm_hour = 0;
- day_components.tm_min = 0;
- day_components.tm_sec = 0;
+ auto time_utils::start_of_a_day_from_timestamp(timestamp timestamp) -> time_utils::timestamp {
+ auto day_components = *day_components_from_timestamp(×tamp);
- timestamp = timestamp_from_day_components(&day_components);
+ day_components.tm_hour = 0;
+ day_components.tm_min = 0;
+ day_components.tm_sec = 0;
- return timestamp;
-}
+ timestamp = timestamp_from_day_components(&day_components);
-time_utils::duration time_utils::current_day_duration() {
- using namespace std::chrono;
+ return timestamp;
+ }
- auto clock_now = system_clock::now();
- auto current_timestamp = system_clock::to_time_t(clock_now);
+ auto time_utils::current_day_duration() -> duration {
+ using namespace std::chrono;
- auto start_of_a_day_timestamp = start_of_a_day_from_timestamp(current_timestamp);
- auto clock_start_of_today = system_clock::from_time_t(start_of_a_day_timestamp);
+ auto clock_now = system_clock::now();
+ auto current_timestamp = system_clock::to_time_t(clock_now);
- return clock_now - clock_start_of_today;
-}
+ auto start_of_a_day_timestamp = start_of_a_day_from_timestamp(current_timestamp);
+ auto clock_start_of_today = system_clock::from_time_t(start_of_a_day_timestamp);
-std::string time_utils::human_string_from_minutes(time_utils::minutes minutes) {
- if (minutes < 1) {
- return "Less than 1 min";
+ return clock_now - clock_start_of_today;
}
- unsigned int hours = minutes / 60;
- unsigned int mins_remainder = minutes - hours * 60;
-
- std::string result;
+ auto time_utils::human_string_from_minutes(minutes minutes) -> std::string {
+ if (minutes < 1) {
+ return "Less than 1 min";
+ }
- if (hours > 0) {
- result += std::to_string(hours);
- }
+ unsigned int hours = minutes / 60;
+ unsigned int mins_remainder = minutes - hours * 60;
- if (hours > 0 && mins_remainder == 30) {
- result += ".5 h";
- } else if (hours > 0) {
- result += " h";
- }
+ std::string result;
- if (mins_remainder != 0) {
if (hours > 0) {
- if (mins_remainder == 30) {
- return result;
+ result += std::to_string(hours);
+ }
+
+ if (hours > 0 && mins_remainder == 30) {
+ result += ".5 h";
+ } else if (hours > 0) {
+ result += " h";
+ }
+
+ if (mins_remainder != 0) {
+ if (hours > 0) {
+ if (mins_remainder == 30) {
+ return result;
+ }
+
+ result += " ";
}
- result += " ";
+ result += std::to_string(mins_remainder) + " min";
}
- result += std::to_string(mins_remainder) + " min";
+ return result;
}
- return result;
-}
-
-std::string time_utils::string_from_seconds(time_utils::minutes total_seconds) {
- auto hours = total_seconds / 3600;
- auto minutes = (total_seconds - 3600 * hours) / 60;
- auto seconds = total_seconds - 3600 * hours - 60 * minutes;
+ auto time_utils::string_from_seconds(minutes total_seconds) -> std::string {
+ auto hours = total_seconds / 3600;
+ auto minutes = (total_seconds - 3600 * hours) / 60;
+ auto seconds = total_seconds - 3600 * hours - 60 * minutes;
- std::string result = std::to_string(hours) + " h";
+ std::string result = std::to_string(hours) + " h";
- if (minutes)
- result += " " + std::to_string(minutes) + " m";
+ if (minutes)
+ result += " " + std::to_string(minutes) + " m";
- if (seconds)
- result += " " + std::to_string(seconds) + "s";
+ if (seconds)
+ result += " " + std::to_string(seconds) + "s";
- return result;
-}
+ return result;
+ }
};
diff --git a/models/time_utils.h b/models/time_utils.h
index 5c67ce3..62de079 100644
--- a/models/time_utils.h
+++ b/models/time_utils.h
@@ -21,13 +21,13 @@ namespace stg {
constexpr static auto day_components_from_timestamp = std::localtime;
constexpr static auto timestamp_from_day_components = std::mktime;
- timestamp start_of_a_day_from_timestamp(timestamp timestamp);
- duration current_day_duration();
- minutes current_minutes();
- seconds current_seconds();
+ auto start_of_a_day_from_timestamp(timestamp timestamp) -> time_utils::timestamp;
+ auto current_day_duration() -> duration;
+ auto current_minutes() -> minutes;
+ auto current_seconds() -> seconds;
- std::string string_from_seconds(minutes total_seconds);
- std::string human_string_from_minutes(minutes minutes);
+ auto string_from_seconds(minutes total_seconds) -> std::string;
+ auto human_string_from_minutes(minutes minutes) -> std::string;
};
}
diff --git a/models/timeslotsstate.cpp b/models/timeslotsstate.cpp
index 85f4590..d906d45 100644
--- a/models/timeslotsstate.cpp
+++ b/models/timeslotsstate.cpp
@@ -12,12 +12,21 @@ stg::time_slots_state::time_t stg::time_slots_state::begin_time() const {
}
void stg::time_slots_state::set_begin_time(time_t begin_time) {
+ if (begin_time == _begin_time)
+ return;
+
_begin_time = begin_time;
+
+ auto max_number_of_slots = 24 * 60 / slot_duration();
+ while (number_of_slots() > max_number_of_slots) {
+ _data.pop_back();
+ }
+
update_begin_times();
+
on_change_event();
}
-
void stg::time_slots_state::update_begin_times() {
for (auto slot_index = 0; slot_index < number_of_slots(); slot_index++) {
_data[slot_index].begin_time
@@ -30,6 +39,9 @@ stg::time_slots_state::duration_t stg::time_slots_state::slot_duration() const {
}
void stg::time_slots_state::set_slot_duration(duration_t slot_duration) {
+ if (slot_duration == _slot_duration)
+ return;
+
_slot_duration = slot_duration;
for (auto slot_index = 0; slot_index < number_of_slots(); slot_index++) {
@@ -74,6 +86,19 @@ stg::time_slots_state::time_slots_state(std::vector from_vector) {
reset_times();
}
+void stg::time_slots_state::set_end_time(time_t end_time) {
+ if (end_time <= begin_time()) {
+ end_time += 24 * 60;
+ }
+
+ auto number_of_slots = (end_time - begin_time()) / slot_duration();
+ set_number_of_slots(number_of_slots);
+}
+
+auto stg::time_slots_state::end_time() const -> time_t {
+ return last().end_time();
+}
+
void stg::time_slots_state::reset_times() {
auto first_slot = _data.front();
_begin_time = first_slot.begin_time;
diff --git a/models/timeslotsstate.h b/models/timeslotsstate.h
index ca22110..d469904 100644
--- a/models/timeslotsstate.h
+++ b/models/timeslotsstate.h
@@ -61,6 +61,9 @@ namespace stg {
size_t number_of_slots() const;
void set_number_of_slots(size_t new_number_of_slots);
+ auto end_time() const -> time_t;
+ void set_end_time(time_t end_time);
+
void set_activity_at_indices(activity *activity,
const std::vector &indices);
diff --git a/ui/activityeditormenu.cpp b/ui/activityeditormenu.cpp
index cd944f2..cb0c721 100644
--- a/ui/activityeditormenu.cpp
+++ b/ui/activityeditormenu.cpp
@@ -53,11 +53,12 @@ void ActivityEditorMenu::setupColorDialog() {
void ActivityEditorMenu::addCustomColorAction() {
customColorAction = new QAction(tr("Custom Color"));
customColorAction->setCheckable(true);
+
customColorAction->setChecked(!colorPicker->color());
connect(customColorAction, &QAction::triggered, [=]() {
if (activity) {
- colorDialog->setCurrentColor(ColorUtils::QColorFromStdString(activity->color()));
+ colorDialog->setCurrentColor(activity->color());
} else if (colorPicker->color()) {
colorDialog->setCurrentColor(*colorPicker->color());
}
diff --git a/ui/application.cpp b/ui/application.cpp
index 29e8d0c..7d87ac1 100644
--- a/ui/application.cpp
+++ b/ui/application.cpp
@@ -6,6 +6,7 @@
#include
#include "application.h"
+#include "colorprovider.h"
#ifdef Q_OS_WIN
@@ -144,6 +145,20 @@ void Application::clearRecentFiles() {
#endif
}
+auto Application::theme() -> const stg::theme & {
+ static auto theme = stg::theme();
+
+ theme.get_text_color = [] {
+ return ColorProvider::textColor();
+ };
+
+ theme.get_base_color = [] {
+ return ColorProvider::baseColor();
+ };
+
+ return theme;
+}
+
#ifdef Q_OS_WIN
void Application::checkForUpdates() {
diff --git a/ui/application.h b/ui/application.h
index 86f0894..58f2679 100644
--- a/ui/application.h
+++ b/ui/application.h
@@ -13,6 +13,7 @@
#include "aboutwindow.h"
#include "mainwindow.h"
+#include "models/theme.h"
#ifdef Q_OS_MAC
Q_FORWARD_DECLARE_OBJC_CLASS(CocoaDelegate);
@@ -35,6 +36,7 @@ class Application : public QApplication {
static void markFileClosed(const QString &filePath);
static bool fileIsOpened(const QString &filePath);
static void checkForUpdates();
+ static auto theme() -> const stg::theme &;
private:
static void setupFonts();
diff --git a/ui/colorpicker.cpp b/ui/colorpicker.cpp
index 1f63b2f..e27722c 100644
--- a/ui/colorpicker.cpp
+++ b/ui/colorpicker.cpp
@@ -9,10 +9,8 @@
ColorPicker::ColorPicker(QWidget *parent) : QWidget(parent) {
auto *mainLayout = new QHBoxLayout(this);
mainLayout->setSpacing(0);
- mainLayout->setContentsMargins(0,
- 0,
- 0,
- 0);
+ mainLayout->setContentsMargins(0, 0, 0, 0);
+
for (const auto &color : colors) {
auto *item = new ColorPickerItem(color, this);
connect(item,
@@ -34,12 +32,13 @@ void ColorPicker::setColor(const std::optional &color) {
if (!color)
return deselectAll();
- auto indexOfColor = std::distance(colors.begin(), std::find(colors.begin(), colors.end(), *color));
- if (indexOfColor < 0)
+ auto it = std::find(colors.begin(), colors.end(), *color);
+ if (it == colors.end())
return deselectAll();
_color = color;
+ auto indexOfColor = std::distance(colors.begin(), it);
for (auto i = 0; i < layout()->count(); i++) {
auto *item = qobject_cast(layout()->itemAt(i)->widget());
item->setIsSelected(indexOfColor == i);
diff --git a/ui/colorprovider.cpp b/ui/colorprovider.cpp
index 9fabdfd..0c596f7 100644
--- a/ui/colorprovider.cpp
+++ b/ui/colorprovider.cpp
@@ -31,13 +31,15 @@ QColor ColorProvider::selectionColor() {
return selectionColor;
}
-//#ifndef Q_OS_MAC
+#ifndef Q_OS_MAC
QColor ColorProvider::controlColor() {
- return highlightColor();
+ auto color = highlightColor();
+ color.setHsvF(color.hueF(), 1.0, color.valueF());
+ return color;
}
-//#endif
+#endif
QColor ColorProvider::textColor() {
return QApplication::palette().color(QPalette::Text);
diff --git a/ui/colorprovider.mm b/ui/colorprovider.mm
index ce0c2ca..2893d09 100644
--- a/ui/colorprovider.mm
+++ b/ui/colorprovider.mm
@@ -7,10 +7,16 @@
#include "colorprovider.h"
-//QColor ColorProvider::controlColor() {
-// NSColor *nsColor = [NSColor controlAccentColor];
-// return QColor(static_cast(nsColor.redComponent * 255),
-// static_cast(nsColor.greenComponent * 255),
-// static_cast(nsColor.blueComponent * 255),
-// static_cast(nsColor.alphaComponent * 255));
-//}
\ No newline at end of file
+QColor ColorProvider::controlColor() {
+ NSColor *nsColor;
+ if (@available(macOS 10.14, *)) {
+ nsColor = [[NSColor controlAccentColor] colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
+ } else {
+ nsColor = [[NSColor linkColor] colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
+ }
+
+ return QColor(static_cast(nsColor.redComponent * 255),
+ static_cast(nsColor.greenComponent * 255),
+ static_cast(nsColor.blueComponent * 255),
+ static_cast(nsColor.alphaComponent * 255));
+}
\ No newline at end of file
diff --git a/ui/selectionwidget.cpp b/ui/selectionwidget.cpp
index f358e10..67b0404 100644
--- a/ui/selectionwidget.cpp
+++ b/ui/selectionwidget.cpp
@@ -39,9 +39,8 @@ void SelectionWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
- auto penColor = selectionColor();
- penColor.setAlphaF(1.0);
- penColor.setHsvF(penColor.hueF(), penColor.saturationF(), 1.0, 1.0);
+ auto penColor = controlColor();
+ penColor.setAlphaF(0.5);
painter.setPen(QPen(penColor, 1));
// painter.setPen(Qt::NoPen);
@@ -53,7 +52,7 @@ void SelectionWidget::paintEvent(QPaintEvent *event) {
? clickedColor
: selectionColor());
- for (auto &selectionItem : selection.grouped()) {
+ for (const auto &selectionItem : selection.grouped()) {
drawSelectionForItem(selectionItem, painter);
}
}
@@ -66,9 +65,9 @@ void SelectionWidget::drawSelectionForItem(const stg::grouped_selection_element
const auto &lastTimeSlot = strategy.time_slots()[selectionItem.back()];
auto bottomMargin = lastTimeSlot.end_time() % 60 == 0 ? 1 : 0;
- auto rect = QRect(contentsMargins().left(),
+ auto rect = QRect(contentsMargins().left() + 1,
contentsMargins().top() + topPosition + 2,
- width() - contentsMargins().right() - contentsMargins().left(),
+ width() - contentsMargins().right() - contentsMargins().left() - 1,
widgetHeight - bottomMargin - 5);
painter.drawRoundedRect(rect, 4, 4);
diff --git a/ui/sessionwidget.cpp b/ui/sessionwidget.cpp
index cd7dc99..e8b82ca 100644
--- a/ui/sessionwidget.cpp
+++ b/ui/sessionwidget.cpp
@@ -14,7 +14,9 @@
#include "strategy.h"
#include "colorutils.h"
#include "fontutils.h"
+#include "application.h"
#include "applicationsettings.h"
+#include "theme.h"
SessionWidget::SessionWidget(stg::session activitySession,
QWidget *parent)
@@ -52,23 +54,12 @@ void SessionWidget::paintEvent(QPaintEvent *) {
}
void SessionWidget::drawRulers(QPainter &painter) const {
- auto blackColor = QColor(Qt::black);
- auto desaturatedColor = sessionColor();
- desaturatedColor.setHslF(desaturatedColor.hueF(), 0.3, 0.75);
-
- auto rulerColor = isSelected()
- ? ColorUtils::overlayWithAlpha(blackColor, 0.3, selectedBackgroundColor())
- : desaturatedColor;
-
- if (isSelected() && rulerColor.lightnessF() < 0.1) {
- rulerColor = QColor(Qt::white);
- }
-
- rulerColor.setAlphaF(0.2);
+ QColor rulerColor = Application::theme()
+ .session_ruler_color(activitySession, isSelected());
painter.setBrush(rulerColor);
- for (auto &timeSlot : activitySession.time_slots) {
+ for (const auto &timeSlot : activitySession.time_slots) {
auto timeSlotIndex = static_cast(&timeSlot - &activitySession.time_slots[0]);
if (timeSlotIndex == activitySession.length() - 1) {
@@ -90,44 +81,29 @@ void SessionWidget::drawBackground(QPainter &painter) const {
return;
}
- auto color = isSelected() ? selectedBackgroundColor() : backgroundColor();
+ QColor color = Application::theme()
+ .session_background_color(activitySession, isSelected());
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(color);
auto lastTimeSlot = activitySession.time_slots.back();
auto bottomMargin = lastTimeSlot.end_time() % 60 == 0 || isBorderSelected ? 1 : 0;
- auto selectionRect = QRect(0,
- 2,
- width(),
- height() - 5 - bottomMargin);
-
- painter.drawRoundedRect(selectionRect, 4, 4);
-}
-
-QColor SessionWidget::backgroundColor() const {
- using namespace ColorUtils;
-
- if (!activitySession.activity) {
- return QColor(255, 255, 255, 255);
- }
+ auto backgroundRect = QRect(0,
+ 2,
+ width(),
+ height() - 5 - bottomMargin);
- auto backgroundColor = sessionColor();
- backgroundColor.setAlphaF(0.15);
-
- return backgroundColor;
+ painter.drawRoundedRect(backgroundRect, 4, 4);
}
QColor SessionWidget::selectedBackgroundColor() const {
- auto selectedBackgroundColor = backgroundColor();
- selectedBackgroundColor.setAlphaF(1);
-
- return selectedBackgroundColor;
+ return QColor(activitySession.activity->color());
}
QColor SessionWidget::sessionColor() const {
auto color = activitySession.activity
- ? QColor(QString::fromStdString(activitySession.activity->color()))
+ ? QColor(activitySession.activity->color())
: QColor();
return color;
}
@@ -195,8 +171,7 @@ void SessionWidget::updateUI() {
previousEndTime = activitySession.end_time();
}
-void SessionWidget::setActivitySession(
- const stg::session &newActivitySession) {
+void SessionWidget::setActivitySession(const stg::session &newActivitySession) {
activitySession = newActivitySession;
updateUI();
}
@@ -210,40 +185,23 @@ int SessionWidget::expectedHeight() {
}
void SessionWidget::drawLabel(QPainter &painter) const {
+ using namespace ApplicationSettings;
+
auto font = QFont();
font.setBold(true);
- font.setPixelSize(ApplicationSettings::sessionFontSize);
+ font.setPixelSize(sessionFontSize);
painter.setFont(font);
- auto textRect = QRect(ApplicationSettings::defaultPadding,
- ApplicationSettings::defaultPadding,
- width() - 2 * ApplicationSettings::defaultPadding,
- height() - 2 * ApplicationSettings::defaultPadding);
-
- auto sessionColorDesaturated
- = ColorUtils::overlayWithAlpha(textColor(), 0.5, selectedBackgroundColor());
- sessionColorDesaturated.setHsvF(sessionColorDesaturated.hueF(), 0.2, 0.5);
-
- auto selectedDurationColor
- = ColorUtils::overlayWithAlpha(baseColor(), 0.7, selectedBackgroundColor());
-
- auto durationColor = isSelected()
- ? selectedDurationColor
- : sessionColorDesaturated;
+ auto textRect = QRect(defaultPadding,
+ defaultPadding,
+ width() - 2 * defaultPadding,
+ height() - 2 * defaultPadding);
- auto titleColor = isSelected() ? Qt::white : sessionColor();
-
- if (sessionColor() == QColor(Qt::black)) {
- titleColor = textColor();
- }
-
- if (sessionColor().lightnessF() < 0.2) {
- if (isSelected()) {
- titleColor = Qt::white;
- durationColor = ColorUtils::overlayWithAlpha(Qt::white, 0.5, sessionColor());
- }
- }
+ auto durationColor = Application::theme()
+ .session_duration_color(activitySession, isSelected());
+ auto titleColor = Application::theme()
+ .session_title_color(activitySession, isSelected());
FontUtils::drawSessionTitle(activitySession,
painter,
diff --git a/ui/sessionwidget.h b/ui/sessionwidget.h
index 02f05a9..b500c41 100644
--- a/ui/sessionwidget.h
+++ b/ui/sessionwidget.h
@@ -47,7 +47,6 @@ Q_OBJECT
void updateUI();
int expectedHeight();
- QColor backgroundColor() const;
QColor selectedBackgroundColor() const;
QColor sessionColor() const;
diff --git a/ui/slotboardcircleswidget.cpp b/ui/slotboardcircleswidget.cpp
index 8dbf1c8..82a3949 100644
--- a/ui/slotboardcircleswidget.cpp
+++ b/ui/slotboardcircleswidget.cpp
@@ -32,21 +32,21 @@ void SlotBoardCirclesWidget::paintEvent(QPaintEvent *event) {
auto slotsRect = getSlotsRect();
- auto radius = 6;
+ auto diameter = 6;
auto firstSlotTopOffset = slotsRect.top() + 2;
auto topOffset = firstSlotTopOffset
+ (_slotBeforeResizeBoundaryIndex + 1) * getSlotHeight()
- - 1 - radius / 2;
+ - 1 - diameter / 2;
- auto circleLeftRect = QRect(slotsRect.left() + defaultPadding / 2 - 1,
+ auto circleLeftRect = QRect(slotsRect.left() - defaultPadding / 2 - 1,
topOffset,
- radius,
- radius);
- auto circleRightRect = QRect(slotsRect.right() - radius - defaultPadding + defaultPadding / 2 + 2,
+ diameter,
+ diameter);
+ auto circleRightRect = QRect(slotsRect.right() - diameter - defaultPadding + defaultPadding / 2 + 2,
topOffset,
- radius,
- radius);
+ diameter,
+ diameter);
painter.drawEllipse(circleLeftRect);
painter.drawEllipse(circleRightRect);
diff --git a/ui/slotboardwidget.cpp b/ui/slotboardwidget.cpp
index 269b5bc..546cbce 100644
--- a/ui/slotboardwidget.cpp
+++ b/ui/slotboardwidget.cpp
@@ -23,6 +23,8 @@ SlotBoardWidget::SlotBoardWidget(stg::strategy &strategy, QWidget *parent)
auto *mainLayout = new QHBoxLayout();
setLayout(mainLayout);
+ setMouseTracking(true);
+
layout()->setSpacing(0);
layout()->setContentsMargins(0, 0, 0, 0);
@@ -43,19 +45,18 @@ void SlotBoardWidget::setupCurrentTimeTimer() {
}
void SlotBoardWidget::layoutChildWidgets(QHBoxLayout *mainLayout) {
- slotsWidget = new SlotsWidget(strategy);
- connect(slotsWidget,
+ _slotsWidget = new SlotsWidget(strategy, this);
+ connect(_slotsWidget,
&SlotsWidget::sessionsChanged,
this,
&SlotBoardWidget::handleTimeSlotsChange);
-
- slotRuler = new SlotRuler(makeLabelsForStrategy(),
- slotsWidget->slotHeight());
+ slotRuler = new SlotRuler(makeLabels(),
+ _slotsWidget->slotHeight(), this);
_slotsLayout = new QVBoxLayout();
_slotsLayout->setSpacing(0);
- _slotsLayout->addWidget(slotsWidget);
+ _slotsLayout->addWidget(_slotsWidget);
_slotsLayout->addStretch();
updateSlotsLayout();
@@ -64,16 +65,26 @@ void SlotBoardWidget::layoutChildWidgets(QHBoxLayout *mainLayout) {
mainLayout->addLayout(_slotsLayout);
circlesWidget = new SlotBoardCirclesWidget(
- std::bind(&SlotsWidget::slotHeight, slotsWidget),
- std::bind(&SlotsWidget::geometry, slotsWidget),
+ std::bind(&SlotsWidget::slotHeight, _slotsWidget),
+ std::bind(&SlotsWidget::geometry, _slotsWidget),
this
);
- connect(slotsWidget,
+ connect(_slotsWidget,
&SlotsWidget::resizeBoundaryChanged,
circlesWidget,
&SlotBoardCirclesWidget::updateResizeBoundary);
+ connect(_slotsWidget,
+ &SlotsWidget::resizeBoundaryChanged,
+ slotRuler,
+ &SlotRuler::updateList);
+
+ connect(_slotsWidget,
+ &SlotsWidget::drawDraggedSession,
+ this,
+ &SlotBoardWidget::drawDraggedSession);
+
circlesWidget->setGeometry(geometry());
currentTimeMarkerWidget = new CurrentTimeMarkerWidget(this);
@@ -82,24 +93,25 @@ void SlotBoardWidget::layoutChildWidgets(QHBoxLayout *mainLayout) {
}
void SlotBoardWidget::updateSlotsLayout() const {
- _slotsLayout->setContentsMargins(0, slotsWidget->slotHeight() / 2, 0, 0);
+ _slotsLayout->setContentsMargins(0, _slotsWidget->slotHeight() / 2, 0, 0);
}
void SlotBoardWidget::reloadStrategy() {
- slotsWidget->reloadStrategy();
+ _slotsWidget->reloadStrategy();
updateUI();
}
void SlotBoardWidget::updateUI() {
- slotRuler->setLabels(makeLabelsForStrategy());
+ slotRuler->setLabels(makeLabels());
updateCurrentTimeMarker();
}
-QVector SlotBoardWidget::makeLabelsForStrategy() {
+QVector SlotBoardWidget::makeLabels() {
QVector labels;
for (auto &time : strategy.time_slots().times()) {
+ auto minutes = time % 60;
auto labelText = QStringForMinutes(time);
auto label = TimeLabel{labelText, time};
@@ -110,14 +122,14 @@ QVector SlotBoardWidget::makeLabelsForStrategy() {
}
void SlotBoardWidget::clearSelection() {
- slotsWidget->deselectAllSlots();
+ _slotsWidget->deselectAllSlots();
}
void SlotBoardWidget::updateCurrentTimeMarker() {
auto currentTimeMarker = stg::current_time_marker(strategy);
- auto rect = currentTimeMarker.rect_in_parent(slotsWidget->geometry(),
- CurrentTimeMarkerWidget::markerSize);
+ auto parentRect = _slotsWidget->geometry();
+ auto rect = currentTimeMarker.rect_in_parent(parentRect, CurrentTimeMarkerWidget::markerSize);
currentTimeMarkerWidget->setGeometry(rect);
@@ -133,8 +145,8 @@ void SlotBoardWidget::updateCurrentTimeMarker() {
void SlotBoardWidget::focusOnCurrentTime() {
auto topOffset = stg::current_time_marker(strategy)
- .scroll_offset_in_parent(slotsWidget->geometry(),
- parentWidget()->contentsRect().height());
+ .scroll_offset(_slotsWidget->geometry(),
+ parentWidget()->contentsRect().height());
auto scrollBar = parentScrollArea()->verticalScrollBar();
@@ -153,7 +165,7 @@ QScrollArea *SlotBoardWidget::parentScrollArea() {
void SlotBoardWidget::handleTimeSlotsChange() {
updateCurrentTimeMarker();
- slotRuler->setLabels(makeLabelsForStrategy());
+ slotRuler->setLabels(makeLabels());
emit timeSlotsChange();
}
@@ -182,3 +194,105 @@ QVBoxLayout *SlotBoardWidget::slotsLayout() const {
return _slotsLayout;
}
+SlotsWidget *SlotBoardWidget::slotsWidget() const {
+ return _slotsWidget;
+}
+
+void SlotBoardWidget::drawDraggedSession(int sessionIndex, int firstSlotIndex) {
+ auto getRect = [=]() -> QRect {
+ const auto &session = strategy.sessions()[sessionIndex];
+
+ auto lastSlotIndex = firstSlotIndex + session.length();
+ const auto &lastSlot = strategy.time_slots()[lastSlotIndex];
+ auto bottomMargin = lastSlot.end_time() % 60 == 0 ? 2 : 4;
+ auto horizontalMargin = 8;
+ auto rect = QRect(slotRuler->width(),
+ firstSlotIndex * slotsWidget()->slotHeight() + slotsWidget()->geometry().top() + 2,
+ slotsWidget()->width() - horizontalMargin,
+ session.length() * slotsWidget()->slotHeight() - bottomMargin);
+
+ return rect;
+ };
+
+ auto makeBigRect = [=](const QRect &smallRect) -> QRect {
+ auto bigRect = smallRect;
+ bigRect.setX(smallRect.x() - 2);
+ bigRect.setWidth(smallRect.width() + 4);
+ return bigRect;
+ };
+
+ auto makeSmallRect = [=](const QRect &bigRect) -> QRect {
+ auto smallRect = bigRect;
+ smallRect.setX(bigRect.x() + 2);
+ smallRect.setWidth(bigRect.width() - 4);
+ return smallRect;
+ };
+
+ bool initial = false;
+
+ if (!draggedSessionWidget && sessionIndex >= 0) {
+ initial = true;
+
+ draggedSessionWidget = new SessionWidget(strategy.sessions()[sessionIndex], this);
+ draggedSessionWidget->setDrawsBorders(false);
+ draggedSessionWidget->setIsSelected(true);
+
+ auto shadowColor = textColor();
+ shadowColor.setAlphaF(0.2);
+
+ auto *effect = new QGraphicsDropShadowEffect;
+ effect->setBlurRadius(25);
+ effect->setXOffset(0);
+ effect->setYOffset(0);
+ effect->setColor(shadowColor);
+
+ draggedSessionWidget->setGraphicsEffect(effect);
+
+ draggedSessionWidget->setVisible(true);
+
+ draggedSessionAnimation = new QPropertyAnimation(draggedSessionWidget, "geometry");
+ draggedSessionAnimation->setDuration(50);
+
+ auto smallRect = getRect();
+ auto bigRect = makeBigRect(smallRect);
+
+ draggedSessionWidget->setGeometry(smallRect);
+ draggedSessionAnimation->setStartValue(smallRect);
+ draggedSessionAnimation->setEndValue(bigRect);
+
+ draggedSessionAnimation->start();
+ }
+
+ if (draggedSessionWidget && sessionIndex < 0) {
+ if (draggedSessionAnimation)
+ draggedSessionAnimation->deleteLater();
+
+ draggedSessionAnimation = new QPropertyAnimation(draggedSessionWidget, "geometry");
+ draggedSessionAnimation->setDuration(50);
+ auto draggedSessionWidgetLocal = draggedSessionWidget;
+ draggedSessionWidget = nullptr;
+
+ connect(draggedSessionAnimation, &QPropertyAnimation::finished, [this, draggedSessionWidgetLocal]() {
+ draggedSessionAnimation->deleteLater();
+ draggedSessionWidgetLocal->deleteLater();
+
+ draggedSessionAnimation = nullptr;
+ });
+
+ auto smallRect = makeSmallRect(draggedSessionWidgetLocal->geometry());
+
+ draggedSessionAnimation->setStartValue(draggedSessionWidgetLocal->geometry());
+ draggedSessionAnimation->setEndValue(smallRect);
+
+ draggedSessionAnimation->start();
+ }
+
+ if (draggedSessionWidget && !initial) {
+ auto smallRect = getRect();
+ auto bigRect = makeBigRect(smallRect);
+
+ draggedSessionAnimation->stop();
+ draggedSessionWidget->setGeometry(bigRect);
+ }
+}
+
diff --git a/ui/slotboardwidget.h b/ui/slotboardwidget.h
index 802b87c..886e7d3 100644
--- a/ui/slotboardwidget.h
+++ b/ui/slotboardwidget.h
@@ -3,6 +3,7 @@
#include
#include
+#include
#include "strategy.h"
#include "currenttimemarkerwidget.h"
@@ -28,25 +29,28 @@ Q_OBJECT
void clearSelection();
void focusOnCurrentTime();
+
QVBoxLayout *slotsLayout() const;
+ SlotsWidget *slotsWidget() const;
+
signals:
void timerTick();
void timeSlotsChange();
private:
stg::strategy &strategy;
- SlotsWidget *slotsWidget = nullptr;
+ SlotsWidget *_slotsWidget = nullptr;
SlotBoardCirclesWidget *circlesWidget = nullptr;
+ SessionWidget *draggedSessionWidget = nullptr;
SlotRuler *slotRuler = nullptr;
QVBoxLayout *_slotsLayout = nullptr;
+ QPropertyAnimation *draggedSessionAnimation = nullptr;
QTimer *currentTimeTimer = nullptr;
CurrentTimeMarkerWidget *currentTimeMarkerWidget = nullptr;
- int slotBeforeResizeBoundaryIndex = -2;
-
- QVector makeLabelsForStrategy();
+ QVector makeLabels();
void handleTimeSlotsChange();
void updateUI();
@@ -56,11 +60,12 @@ Q_OBJECT
QScrollArea *parentScrollArea();
void setupCurrentTimeTimer();
void timerCallback();
+ void updateSlotsLayout() const;
+ void drawDraggedSession(int, int);
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
- void updateSlotsLayout() const;
};
#endif // SLOTBOARD_H
diff --git a/ui/slotruler.cpp b/ui/slotruler.cpp
index cc1262c..05ad7e5 100644
--- a/ui/slotruler.cpp
+++ b/ui/slotruler.cpp
@@ -1,10 +1,13 @@
-#include "slotruler.h"
#include
#include
#include
#include
+
#include "applicationsettings.h"
#include "utils.h"
+#include "slotruler.h"
+#include "slotboardwidget.h"
+#include "slotswidget.h"
SlotRuler::SlotRuler(const QVector &labels,
int cellHeight,
@@ -13,15 +16,17 @@ SlotRuler::SlotRuler(const QVector &labels,
_cellHeight(cellHeight),
QWidget(parent) {
auto *layout = new QVBoxLayout();
- layout->setContentsMargins(ApplicationSettings::defaultPadding, 0, 0, 0);
+ layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
setLayout(layout);
- auto fontWidth = calculateLabelWidth() + ApplicationSettings::defaultPadding;
+ auto fontWidth = calculateLabelWidth() + 2 * ApplicationSettings::defaultPadding;
auto width = std::max(fontWidth, 40);
setFixedWidth(width);
updateList();
+
+ selection().add_on_change_callback(this, &SlotRuler::updateList);
}
int SlotRuler::calculateLabelWidth() const {
@@ -45,10 +50,38 @@ void SlotRuler::setLabels(const QVector &labels) {
}
void SlotRuler::paintEvent(QPaintEvent *) {
- QStyleOption opt;
- opt.init(this);
QPainter p(this);
- style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+
+ auto handleBorderColor = highlightColor();
+ handleBorderColor.setAlphaF(0.25);
+
+ auto handleBgColor = highlightColor();
+ handleBgColor.setAlphaF(0.1);
+
+ p.setBrush(handleBgColor);
+ p.setPen(handleBorderColor);
+
+// for (auto &selectionSegment : selection().grouped()) {
+// auto firstIndex = selectionSegment.front();
+// auto lastIndex = selectionSegment.back() + 1;
+//
+// auto handleWidth = calculateLabelWidth() + 4;
+// auto handleHeight = bigFontHeight * 1.5;
+//
+// auto rect1 = QRect((width() - handleWidth) / 2,
+// firstIndex * cellHeight() + (cellHeight() - handleHeight) / 2,
+// handleWidth,
+// handleHeight);
+//
+// auto rect2 = QRect((width() - handleWidth) / 2,
+// lastIndex * cellHeight() + (cellHeight() - handleHeight) / 2,
+// handleWidth,
+// handleHeight);
+//
+//
+// p.drawRoundedRect(rect1, 2, 2);
+// p.drawRoundedRect(rect2, 2, 2);
+// }
}
int SlotRuler::cellHeight() const { return _cellHeight; }
@@ -77,6 +110,12 @@ SlotRuler::ColorGetter SlotRuler::labelColorGetterAtIndex(int index) {
auto colorGetter = this->isIntegerHourAtIndex(index)
? &SlotRuler::secondaryTextColor
: &SlotRuler::tertiaryTextColor;
+
+ if (selection().is_boundary(index) ||
+ slotsWidget()->slotBeforeBoundaryIndex() == index - 1)
+ colorGetter = &SlotRuler::controlColor;
+
+
return colorGetter;
}
@@ -99,3 +138,12 @@ bool SlotRuler::isIntegerHourAtIndex(int index) const {
return isIntegerHour;
}
+const stg::selection &SlotRuler::selection() const {
+ return slotsWidget()->selection();
+}
+
+SlotsWidget *SlotRuler::slotsWidget() const {
+ auto slotBoardWidget = qobject_cast(parentWidget());
+ return slotBoardWidget->slotsWidget();
+}
+
diff --git a/ui/slotruler.h b/ui/slotruler.h
index e7bf299..1471068 100644
--- a/ui/slotruler.h
+++ b/ui/slotruler.h
@@ -9,7 +9,9 @@
#include "timelabel.h"
#include "coloredlabel.h"
#include "colorprovider.h"
+#include "selection.h"
+class SlotsWidget;
class SlotRuler : public QWidget,
public ReactiveList,
public ColorProvider {
@@ -22,8 +24,15 @@ Q_OBJECT
const QVector &labels() const;
void setLabels(const QVector &labels);
+ const stg::selection &selection() const;
+
int cellHeight() const;
void setCellHeight(int cellHeight);
+
+ void updateList() {
+ ReactiveList::updateList();
+ }
+
private:
using ColorGetter = QColor (*)();
QVector _labels;
@@ -34,6 +43,8 @@ Q_OBJECT
ColorGetter labelColorGetterAtIndex(int index);
+ SlotsWidget *slotsWidget() const;
+
// ReactiveList
int numberOfItems() override;
QVBoxLayout *listLayout() override;
diff --git a/ui/slotsmousehandler.cpp b/ui/slotsmousehandler.cpp
index 7d2b9ec..74eb1dc 100644
--- a/ui/slotsmousehandler.cpp
+++ b/ui/slotsmousehandler.cpp
@@ -31,98 +31,7 @@ SlotsMouseHandler::SlotsMouseHandler(SlotsWidget *slotsWidget)
handler.on_context_menu_event = std::bind(&SlotsMouseHandler::showContextMenu, this, _1, _2, _3);
handler.on_open_activities = std::bind(&SlotsWidget::openActivitiesWindow, slotsWidget);
handler.on_draw_dragged_session = [this](int sessionIndex, int firstSlotIndex) {
- auto getRect = [=]() -> QRect {
- const auto &session = strategy().sessions()[sessionIndex];
-
- auto lastSlotIndex = firstSlotIndex + session.length();
- auto &lastSlot = strategy().time_slots()[lastSlotIndex];
- auto bottomMargin = lastSlot.end_time() % 60 == 0 ? 2 : 4;
- auto horizontalMargin = 8;
- auto rect = QRect(horizontalMargin,
- firstSlotIndex * slotHeight() + 2,
- width() - 2 * horizontalMargin,
- session.length() * slotHeight() - bottomMargin);
-
- return rect;
- };
-
- auto makeBigRect = [=](const QRect &smallRect) -> QRect {
- auto bigRect = smallRect;
- bigRect.setX(smallRect.x() - 2);
- bigRect.setWidth(smallRect.width() + 4);
- return bigRect;
- };
-
- auto makeSmallRect = [=](const QRect &bigRect) -> QRect {
- auto smallRect = bigRect;
- smallRect.setX(bigRect.x() + 2);
- smallRect.setWidth(bigRect.width() - 4);
- return smallRect;
- };
-
- bool initial = false;
-
- if (!draggedSessionWidget && sessionIndex >= 0) {
- initial = true;
-
- draggedSessionWidget = new SessionWidget(strategy().sessions()[sessionIndex], this);
- draggedSessionWidget->setDrawsBorders(false);
- draggedSessionWidget->setIsSelected(true);
-
- auto *effect = new QGraphicsDropShadowEffect;
- effect->setBlurRadius(20);
- effect->setXOffset(0);
- effect->setYOffset(0);
- effect->setColor(QColor(0xCCCCCC));
-
- draggedSessionWidget->setGraphicsEffect(effect);
-
- draggedSessionWidget->setVisible(true);
-
- draggedSessionAnimation = new QPropertyAnimation(draggedSessionWidget, "geometry");
- draggedSessionAnimation->setDuration(50);
-
- auto smallRect = getRect();
- auto bigRect = makeBigRect(smallRect);
-
- draggedSessionWidget->setGeometry(smallRect);
- draggedSessionAnimation->setStartValue(smallRect);
- draggedSessionAnimation->setEndValue(bigRect);
-
- draggedSessionAnimation->start();
- }
-
- if (draggedSessionWidget && sessionIndex < 0) {
- if (draggedSessionAnimation)
- draggedSessionAnimation->deleteLater();
-
- draggedSessionAnimation = new QPropertyAnimation(draggedSessionWidget, "geometry");
- draggedSessionAnimation->setDuration(50);
- auto draggedSessionWidgetLocal = draggedSessionWidget;
- draggedSessionWidget = nullptr;
-
- connect(draggedSessionAnimation, &QPropertyAnimation::finished, [this, draggedSessionWidgetLocal]() {
- draggedSessionAnimation->deleteLater();
- draggedSessionWidgetLocal->deleteLater();
-
- draggedSessionAnimation = nullptr;
- });
-
- auto smallRect = makeSmallRect(draggedSessionWidgetLocal->geometry());
-
- draggedSessionAnimation->setStartValue(draggedSessionWidgetLocal->geometry());
- draggedSessionAnimation->setEndValue(smallRect);
-
- draggedSessionAnimation->start();
- }
-
- if (draggedSessionWidget && !initial) {
- auto smallRect = getRect();
- auto bigRect = makeBigRect(smallRect);
-
- draggedSessionAnimation->stop();
- draggedSessionWidget->setGeometry(bigRect);
- }
+ emit drawDraggedSession(sessionIndex, firstSlotIndex);
};
}
@@ -135,17 +44,15 @@ stg::selection &SlotsMouseHandler::selection() {
}
SlotBoardWidget *SlotsMouseHandler::slotBoard() {
- return qobject_cast
- (slotsWidget->parent());
+ return qobject_cast(slotsWidget->parent());
}
QScrollArea *SlotsMouseHandler::slotBoardScrollArea() {
- return qobject_cast
- (slotsWidget
- ->parent() // layout
- ->parent() // slotboard
- ->parent() // scroll area
- ->parent()) // layout
+ return qobject_cast(slotsWidget
+ ->parent() // layout
+ ->parent() // slotboard
+ ->parent() // scroll area
+ ->parent()) // layout
->slotBoardScrollArea();
}
diff --git a/ui/slotsmousehandler.h b/ui/slotsmousehandler.h
index 123e6d7..3b7adc1 100644
--- a/ui/slotsmousehandler.h
+++ b/ui/slotsmousehandler.h
@@ -27,6 +27,8 @@ Q_OBJECT
signals:
void resizeBoundaryChanged(int sessionBeforeBoundaryIndex,
int slotBeforeBoundaryIndex);
+ void drawDraggedSession(int sessionIndex,
+ int firstSlotIndex);
private:
SlotsWidget *slotsWidget;
@@ -43,8 +45,6 @@ Q_OBJECT
QTimer *autoscrollAnimation = nullptr;
int draggedSessionIndex = -1;
stg::rect draggedSessionRect = stg::rect::zero;
- SessionWidget *draggedSessionWidget = nullptr;
- QPropertyAnimation *draggedSessionAnimation = nullptr;
SessionWidget *sessionWidgetAtIndex(int sessionIndex);
SlotBoardWidget *slotBoard();
diff --git a/ui/slotswidget.cpp b/ui/slotswidget.cpp
index 913b548..1af372a 100644
--- a/ui/slotswidget.cpp
+++ b/ui/slotswidget.cpp
@@ -45,6 +45,11 @@ void SlotsWidget::layoutChildWidgets() {
this,
&SlotsWidget::updateResizeBoundary);
+ connect(mouseHandler,
+ &SlotsMouseHandler::drawDraggedSession,
+ this,
+ &SlotsWidget::drawDraggedSession);
+
layout()->addWidget(slotsWidget);
layout()->addWidget(selectionWidget);
layout()->addWidget(mouseHandler);
@@ -189,32 +194,36 @@ void SlotsWidget::paintEvent(QPaintEvent *event) {
painter.setPen(Qt::NoPen);
- auto borderColor = slotBeforeBoundaryIndex == -1
- ? highlightColor()
+ auto borderColor = _slotBeforeBoundaryIndex == -1
+ ? controlColor()
: ColorProvider::borderColor();
painter.setBrush(borderColor);
auto thickness = strategy.begin_time() % 60 == 0 ? 2 : 1;
- auto borderRect = QRect(8, 0, width() - 8 * 2, thickness);
+ auto borderRect = QRect(0, 0, width() - ApplicationSettings::defaultPadding, thickness);
painter.drawRect(borderRect);
}
void SlotsWidget::updateContentsMargins() {
auto thickness = strategy.begin_time() % 60 == 0 ? 2 : 1;
- slotsLayout->setContentsMargins(8, thickness, 8, 0);
- selectionWidget->setContentsMargins(8, thickness, 8, 0);
+ slotsLayout->setContentsMargins(0, thickness, ApplicationSettings::defaultPadding, 0);
+ selectionWidget->setContentsMargins(0, thickness, ApplicationSettings::defaultPadding, 0);
}
void SlotsWidget::updateResizeBoundary(int sessionBeforeBoundaryIndex,
int slotBeforeBoundaryIndex) {
- this->slotBeforeBoundaryIndex = slotBeforeBoundaryIndex;
+ this->_slotBeforeBoundaryIndex = slotBeforeBoundaryIndex;
update();
emit resizeBoundaryChanged(sessionBeforeBoundaryIndex, slotBeforeBoundaryIndex);
}
+int SlotsWidget::slotBeforeBoundaryIndex() const {
+ return _slotBeforeBoundaryIndex;
+}
+
diff --git a/ui/slotswidget.h b/ui/slotswidget.h
index 4048425..4cff4be 100644
--- a/ui/slotswidget.h
+++ b/ui/slotswidget.h
@@ -27,15 +27,19 @@ Q_OBJECT
explicit SlotsWidget(stg::strategy &strategy,
QWidget *parent = nullptr);
- void reloadStrategy();
int slotHeight() const;
+ void reloadStrategy();
void deselectAllSlots();
+ int slotBeforeBoundaryIndex() const;
+
const stg::selection &selection();
signals:
void sessionsChanged();
void resizeBoundaryChanged(int, int);
+ void drawDraggedSession(int, int);
+
private:
friend SlotsMouseHandler;
stg::strategy &strategy;
@@ -46,7 +50,7 @@ Q_OBJECT
SlotsMouseHandler *mouseHandler = nullptr;
int _slotHeight = ApplicationSettings::defaultSlotHeight;
- int slotBeforeBoundaryIndex = -2;
+ int _slotBeforeBoundaryIndex = -2;
QAction *setActivityAction = nullptr;
QAction *deleteActivityAction = nullptr;
@@ -65,7 +69,8 @@ Q_OBJECT
void updateUI();
void updateContentsMargins();
- void updateResizeBoundary(int sessionBeforeBoundaryIndex, int slotBeforeBoundaryIndex);
+ void updateResizeBoundary(int sessionBeforeBoundaryIndex,
+ int slotBeforeBoundaryIndex);
void onSelectionChange();
diff --git a/ui/strategysettingswidget.cpp b/ui/strategysettingswidget.cpp
index dd39ef5..5cb0ac2 100644
--- a/ui/strategysettingswidget.cpp
+++ b/ui/strategysettingswidget.cpp
@@ -76,7 +76,7 @@ void StrategySettingsWidget::createSlotDurationForm() {
slotDurationEdit->setAlignment(Qt::AlignRight);
slotDurationEdit->setStyleSheet("color: #888;");
- auto slotDurationEditDecorator = new SpinBoxDecorator(slotDurationEdit, this);
+ auto *slotDurationEditDecorator = new SpinBoxDecorator(slotDurationEdit, this);
slotDurationEditDecorator->setSizePolicy(QSizePolicy::Fixed,
QSizePolicy::Fixed);
@@ -215,7 +215,6 @@ void StrategySettingsWidget::save() {
auto slotDuration = slotDurationEdit->value();
auto beginTime = minutesFromQTime(beginTimeEdit->time());
auto endTime = minutesFromQTime(endTimeEdit->time());
- auto numberOfSlots = (endTime - beginTime) / slotDuration;
if (slotDuration != strategy.time_slot_duration()) {
strategy.set_time_slot_duration(slotDuration);
@@ -225,29 +224,12 @@ void StrategySettingsWidget::save() {
strategy.set_begin_time(beginTime);
}
- if (numberOfSlots != strategy.number_of_time_slots()) {
- strategy.set_number_of_time_slots(numberOfSlots);
+ if (endTime != strategy.end_time()) {
+ strategy.set_end_time(endTime);
}
}
void StrategySettingsWidget::endTimeChanged(const QTime &time) {
- auto slotDuration = slotDurationEdit->value();
- auto mins = minutesFromQTime(time);
- if (mins <= minutesFromQTime(beginTimeEdit->time())) {
- endTimeEdit->setTime(beginTimeEdit->time().addSecs(slotDuration * 60));
- return;
- }
-
- auto remainder = mins % slotDuration;
- if (remainder != 0) {
- mins = remainder < slotDuration / 2 ? mins - remainder
- : mins - remainder + slotDuration;
- }
-
- if (mins != minutesFromQTime(time)) {
- endTimeEdit->setTime(QTimeFromMinutes(mins));
- }
-
save();
}