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