-
-
Notifications
You must be signed in to change notification settings - Fork 589
/
HACKING
236 lines (162 loc) · 8.93 KB
/
HACKING
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
Since 1999, people have been hacking on Krita. Everyone brought their
own coding style, their own code conventions, their own likes and
dislikes. Me, (Halla that is), I like indents of four spaces, and
no scope prefixes for variables. However, in the interests of
consistency, these are the rules new code should adhere to:
See also https://community.kde.org/Policies/Frameworks_Coding_Style --
that document is leading.
Qt vs STD vs Boost:
In general, use the Qt classes wherever possible, even if someone tells you
that the STD class is better or whatever. We're dealing with a big project
with lots of developers here and we should keep the code as consistent and
easy to grasp as possible. Since people need to know Qt in the first place,
keep to Qt. Discuss deviations on #krita
C++11 and C++14
Yes, but.
* Prefer normal functions over lambdas, unless really needed (e.g. when replacing
the use of QSignalMapper)
* Try to avoid auto as a shortcut for the type name, except when used
in range-based for-loops and iterators. Using auto as a replacement
for a templated code (or inside templated code) is perfectly fine.
* Generic lambdas. Use generic lambdas only when you want to solve a
problem that would otherwise require templates, not just as a shortcut for
the argument typenames.
* auto as a deduced return type of functions that would otherwise require
templates is perfectly fine
* In some cases it might be okay to use auto as a shortcut for the typename,
e.g. when using very long types returned by boost. But better discuss that
on #krita.
* Avoid the new sig/slot connection syntax _unless_ you are porting all of
Krita to the new syntax. Sure, it has some advantages, but having two different
ways of doing the same thing is begging for trouble and comprehension problems.
* For now, keep using Q_FOREACH, we're using it all over the place, and it has
different constness semantics over the standard range-based for-loop.
* Use nullptr in new code. When changing existing code, make sure that 1) the whole
.cpp/.h files pair uses the same style, 2) the change of the style outweigh the
loss of the git-blame history (that is, your changes do already change the file
significantly)
* Before using other new features, discuss on #krita so we can expand this list.
Indentation
With four spaces. Use the default kdelibs indentation
(http://techbase.kde.org/Policies/Kdelibs_Coding_Style)
Includes
Avoid as much as possible #includes in header files; use forward declarations
of classes.
Initializers
Avoid as much as possible initializers in the body of the constructor. Use
initializer lists instead. Write the initializers as follows
Class(A a, B b)
: Subclass(a)
, m_b(b)
{
}
Note the location of the colon and comma.
It is also preferred to use {}-initialization for class members and
global namespace scope variables, e.g.
class Foo
{
int m_value {0};
};
namespace Bar
{
int SomeGlobalValue {0};
};
Since Krita has a long history of usage =-initialization everywhere, it is **not**
recommended to use {}-initialization in function bodies, especially, when it results
in a mix of styles in the same file. You can still use that as an exception to solve
some specific problems like the most vexing parse.
Scope prefixes
Use only m_ for class-level variables. No other scope prefixes; no g_, l_,
no 'p' for pointer variables.
Shared pointers
Use shared pointers wherever possible. Prefer Qt's shared pointer classes
to our home-grown shared pointer classes.
Getter/setter
Krita doesn't use Qt's properties -- yet. If you want to introduce use of
properties, convert any and all classes in Krita before committing.
Getter/setters are named 'x() for getters and setX(int x) for setters. If you
come across violations of this rule, change the code.
Class naming
If you use a well-known design pattern, name the class according to the design
pattern. All files should start with 'Kis', all classes with the 'Kis' prefix.
This filename should be the same as the classname: KisNewClass.h, KisNewClass.
Filenames in plugins do not start with Kis; only in libraries. Do not make new
classes that start with Ko.
Function naming
Functions should be named in camelBackedFashion, to conform to Qt's standards.
If you encounter functions in c_style_like_this, feel free to rename. Also:
verbNoun -- i.e., rotateLayer, not layer_rotate. The latter is a true c-ism,
introduced by a language that needs to prefix the 'class' name to every function
in order to have something that's not quite OO.
Variable/Parameter names
Variable/parameter names start with a lower case letter. A name composed of different
words is done in camelBackedStyle.
Try to avoid abbreviations except for the most common cases, like cs for KoColorSpace.
It's okay for variable names to be long and explicit and derived from the type name.
Designer
Krita has started to use designer. All dialogs and all widgets that have a layout
manager must be done in designer. Do not add code or signal/slot connections
in designer.
Enums
All enums should be prefixed with 'enum'.
Namespaces
Currently, we only use anonymous namespaces for things like undo
commands. For the rest, some classes have a 'Kis' prefix, others don't. This should
be made consistent, and we might want to use namespaces to keep all of Krita
inside.
Files and classes
It's preferred (and strongly preferred) to have only one class per .h/.cpp file.
(Which is logical, because otherwise you won't be able to keep to the naming scheme.)
Spaces
Keep the source airy and open. In particular, there should be empty lines between function
declarations and definitions.
Slots and signals
Prefix slots with slot and signals with sig: slotUpdateSelection, sigSelectionUpdated.
Boolean operators
Use the standard !, !=, ==, && etc style, not the "not", "and" etc. style. Keep krita code
using one, easily recognizable, C++ style.
Static initializers
Sometimes we need to declare a static object that performs some actions on Krita
loading, e.g. to register Qt's metatype for a Krita type. We have a special macro
for that:
KIS_DECLARE_STATIC_INITIALIZER {
qRegisterMetaType<KoResourceSP>("KoResourceSP");
}
What the macro does is basically defining a static variable that is initialized
on loading of the library:
struct KoResourceSPStaticInitializer {
KoResourceSPStaticInitializer() {
qRegisterMetaType<KoResourceSP>("KoResourceSP");
}
};
static KoResourceSPStaticInitializer __initializer1;
This macro is usually added to the same .cpp file as the class itself.
WARNING: do not use this pattern in **plugins**. All Krita's plugins are
actually static libraries that are pulled into dynamic .so libraries at the
linking stage. It means that all "unused" objects will never be pulled
into the final plugin. Instead, do all the initialization in the "plugin"
class (the one that is passed to registerPlugin<>() in
K_PLUGIN_FACTORY_WITH_JSON).
The problem can be worked around with `$<LINK_LIBRARY:WHOLE_ARCHIVE,...>`
CMake feature, but it is available only since CMake 3.24, so for now
just avoid using initializers in plugins.
With Krita now supporting Python scripting, we need guidelines for these as well.
These guidelines are preliminary and may be further refined in the future.
To keep it simple, we have chosen to follow the style guide suggested by Python: PEP8.
All rules should be followed, except the max limit of 79 characters per line. As this
can reduce readability in some cases, this rule is optional.
The full PEP8 specification is available here: https://www.python.org/dev/peps/pep-0008/
To check compliance you can run pep8.py against the code.
You can also use autopep8.py to automatically fix detected compliance issues.
pep8.py can be downloaded via Python's package manager (pip) [https://pypi.python.org/pypi/pep8],
or your distribution's package manager.
autopep8.py can also be downloaded via Python's package manager [https://pypi.python.org/pypi/autopep8],
or your distribution's package manager.
Both of these scripts come bundled with the PyDev plugin, which is available for Eclipse and other IDEs.
The PyDev integration can be configured to visually highlight portions of the code which is not in compliance,
as well as run autopep8 via shortcuts.
pep8.py and autopep8.py can suppress select rules via the "--ignore" command line argument.
To ignore the 79 characters per line rule, pep8.py can be called like this:
pep8.py --ignore=E501
You can read more about the error codes and what they mean here:
http://pep8.readthedocs.io/en/release-1.7.x/intro.html#error-codes