1// Aseprite
2// Copyright (C) 2019 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifndef APP_PREF_OPTION_H_INCLUDED
9#define APP_PREF_OPTION_H_INCLUDED
10#pragma once
11
12#include "obs/signal.h"
13#include <string>
14
15#ifdef ENABLE_SCRIPTING
16 #include "app/script/values.h"
17#endif
18
19namespace app {
20
21 class OptionBase;
22
23 class Section {
24 public:
25 Section(const std::string& name) : m_name(name) { }
26 virtual ~Section() { }
27 const char* name() const { return m_name.c_str(); }
28
29 virtual Section* section(const char* id) = 0;
30 virtual OptionBase* option(const char* id) = 0;
31
32 obs::signal<void()> BeforeChange;
33 obs::signal<void()> AfterChange;
34
35 private:
36 std::string m_name;
37 };
38
39 class OptionBase {
40 public:
41 OptionBase(Section* section, const char* id)
42 : m_section(section)
43 , m_id(id) {
44 }
45 virtual ~OptionBase() { }
46 const char* section() const { return m_section->name(); }
47 const char* id() const { return m_id; }
48
49#ifdef ENABLE_SCRIPTING
50 virtual void pushLua(lua_State* L) = 0;
51 virtual void fromLua(lua_State* L, int index) = 0;
52#endif
53
54 protected:
55 Section* m_section;
56 const char* m_id;
57 };
58
59 template<typename T>
60 class Option : public OptionBase {
61 public:
62 Option(Section* section, const char* id, const T& defaultValue = T())
63 : OptionBase(section, id)
64 , m_default(defaultValue)
65 , m_value(defaultValue)
66 , m_dirty(false) {
67 }
68
69 const T& operator()() const {
70 return m_value;
71 }
72
73 const T& operator()(const T& newValue) {
74 setValue(newValue);
75 return m_value;
76 }
77
78 // operator=() changes the value and the default value of the
79 // option. E.g. it's used when we copy two complete Sections,
80 // from default settings to user settings, or viceversa (the
81 // default value is always involved).
82 Option& operator=(const Option& opt) {
83 setValueAndDefault(opt.m_value);
84 return *this;
85 }
86
87 // Changes the default value and the current one.
88 void setValueAndDefault(const T& value) {
89 bool wasDirty = isDirty();
90
91 setDefaultValue(value);
92 setValue(value);
93
94 if (!wasDirty)
95 cleanDirtyFlag();
96 }
97
98 const T& defaultValue() const { return m_default; }
99 void setDefaultValue(const T& defValue) {
100 m_default = defValue;
101 }
102
103 bool isDirty() const { return m_dirty; }
104 void forceDirtyFlag() { m_dirty = true; }
105 void cleanDirtyFlag() { m_dirty = false; }
106
107 void setValue(const T& newValue) {
108 if (m_value == newValue) {
109 m_dirty = true;
110 return;
111 }
112
113 BeforeChange(newValue);
114 if (m_section)
115 m_section->BeforeChange();
116
117 m_value = newValue;
118 m_dirty = true;
119
120 AfterChange(newValue);
121 if (m_section)
122 m_section->AfterChange();
123 }
124
125 void clearValue() {
126 m_value = m_default;
127 m_dirty = false;
128 }
129
130#ifdef ENABLE_SCRIPTING
131 void pushLua(lua_State* L) override {
132 script::push_value_to_lua<T>(L, m_value);
133 }
134 void fromLua(lua_State* L, int index) override {
135 setValue(script::get_value_from_lua<T>(L, index));
136 }
137#endif
138
139 obs::signal<void(const T&)> BeforeChange;
140 obs::signal<void(const T&)> AfterChange;
141
142 private:
143 T m_default;
144 T m_value;
145 bool m_dirty;
146
147 Option();
148 Option(const Option& opt);
149 };
150
151} // namespace app
152
153#endif
154