/[svn]/gigedit/trunk/src/gigedit/global.h
ViewVC logotype

Contents of /gigedit/trunk/src/gigedit/global.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3827 - (show annotations) (download) (as text)
Tue Oct 6 16:58:03 2020 UTC (3 years, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 11775 byte(s)
- global.h: Added util function unusedScripts().

1 /* -*- c++ -*-
2 * Copyright (C) 2007-2020 Andreas Persson
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with program; see the file COPYING. If not, write to the Free
16 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #ifndef GIGEDIT_GLOBAL_H
21 #define GIGEDIT_GLOBAL_H
22
23 #if HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <cstring>
28 #include <algorithm>
29
30 #ifdef GLIBMM_HEADER_FILE
31 # include GLIBMM_HEADER_FILE(glibmmconfig.h)
32 #else
33 # include <glibmmconfig.h>
34 #endif
35
36 #if !defined(WIN32)
37 # include <unistd.h>
38 # include <errno.h>
39 #endif
40
41 #include <sstream>
42 #include <map>
43 #ifdef SIGCPP_HEADER_FILE
44 # include SIGCPP_HEADER_FILE(signal.h)
45 #else
46 # include <sigc++/signal.h>
47 #endif
48
49 #ifdef LIBGIG_HEADER_FILE
50 # include LIBGIG_HEADER_FILE(gig.h)
51 # include LIBGIG_HEADER_FILE(Serialization.h)
52 #else
53 # include <gig.h>
54 # include <Serialization.h>
55 #endif
56
57 //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
58 #ifdef GETTEXT_HEADER_FILE
59 # include GETTEXT_HEADER_FILE(libintl.h)
60 #elif (HAVE_GETTEXT || defined(__APPLE__))
61 # include <libintl.h>
62 # define _(String) gettext(String)
63 #else
64 # define _(String) String
65 #endif
66
67 #if defined(WIN32) && !HAVE_CONFIG_H
68 # include "../../win32/libgigedit_private.h" // like config.h, automatically generated by Dev-C++
69 # define PACKAGE "gigedit"
70 # define VERSION VER_STRING // VER_STRING defined in libgig_private.h
71 #endif // WIN32
72
73 #define UNICODE_RIGHT_ARROW Glib::ustring(1, gunichar(0x2192))
74 #define UNICODE_LEFT_ARROW Glib::ustring(1, gunichar(0x2190))
75 #define UNICODE_SHIFT_KEY_SYMBOL Glib::ustring("\xe2\x87\xa7")
76 #if defined(__APPLE__)
77 # define UNICODE_ALT_KEY_SYMBOL Glib::ustring("\xe2\x8c\xa5")
78 #else
79 # define UNICODE_ALT_KEY_SYMBOL Glib::ustring("Alt")
80 #endif
81 #define UNICODE_ERASE_KEY_SYMBOL Glib::ustring("\xe2\x8c\xab")
82 #define UNICODE_CTRL_KEY_SYMBOL Glib::ustring("Ctrl")
83 #define UNICODE_CMD_KEY_SYMBOL Glib::ustring(1, gunichar(0x2318))
84 #if defined(__APPLE__)
85 # define UNICODE_PRIMARY_KEY_SYMBOL UNICODE_CMD_KEY_SYMBOL
86 #else
87 # define UNICODE_PRIMARY_KEY_SYMBOL UNICODE_CTRL_KEY_SYMBOL
88 #endif
89
90 // taken from gdk/gdkkeysyms.h
91 // (define on demand, to avoid unnecessary dev lib package build dependency)
92 #ifndef GDK_KEY_Control_L
93 # define GDK_KEY_Control_L 0xffe3
94 #endif
95 #ifndef GDK_KEY_Control_R
96 # define GDK_KEY_Control_R 0xffe4
97 #endif
98 #ifndef GDK_KEY_Left
99 # define GDK_KEY_Left 0xff51
100 #endif
101 #ifndef GDK_KEY_Right
102 # define GDK_KEY_Right 0xff53
103 #endif
104 #ifndef GDK_KEY_Up
105 # define GDK_KEY_Up 0xff52
106 #endif
107 #ifndef GDK_KEY_Down
108 # define GDK_KEY_Down 0xff54
109 #endif
110
111 #include <glibmm/convert.h>
112
113 #define GIG_STR_ENCODING "CP1252"
114
115 static inline
116 Glib::ustring gig_to_utf8(const gig::String& gig_string) {
117 return Glib::convert_with_fallback(gig_string, "UTF-8", GIG_STR_ENCODING, "?");
118 }
119
120 static inline
121 gig::String gig_from_utf8(const Glib::ustring& utf8_string) {
122 return Glib::convert_with_fallback(utf8_string, GIG_STR_ENCODING, "UTF-8", "?");
123 }
124
125 inline Glib::ustring ltrim(Glib::ustring s) {
126 s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
127 return s;
128 }
129
130 inline Glib::ustring rtrim(Glib::ustring s) {
131 s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
132 return s;
133 }
134
135 inline Glib::ustring trim(Glib::ustring s) {
136 return ltrim(rtrim(s));
137 }
138
139 template<class T> inline std::string ToString(T o) {
140 std::stringstream ss;
141 ss << o;
142 return ss.str();
143 }
144
145 inline static bool endsWith(const std::string& haystack, const std::string& needle, bool caseSensitive) {
146 if (haystack.size() < needle.size()) return false;
147 const std::string sub = haystack.substr(haystack.size() - needle.size(), needle.size());
148 return (caseSensitive) ? (sub == needle) : (!strcasecmp(sub.c_str(), needle.c_str()));
149 }
150
151 inline int getIndexOf(gig::Instrument* instrument) {
152 gig::File* file = (gig::File*) instrument->GetParent();
153 for (int i = 0; true ; ++i) {
154 gig::Instrument* instr = file->GetInstrument(i);
155 if (!instr) break;
156 if (instr == instrument) return i;
157 }
158 return -1;
159 }
160
161 inline int getDimensionIndex(gig::dimension_t type, gig::Region* rgn) {
162 for (uint i = 0; i < rgn->Dimensions; ++i)
163 if (rgn->pDimensionDefinitions[i].dimension == type)
164 return i;
165 return -1;
166 }
167
168 inline int getDimensionRegionIndex(gig::DimensionRegion* dr) {
169 if (!dr) return -1;
170 gig::Region* rgn = (gig::Region*)dr->GetParent();
171 for (uint i = 0; i < 256; ++i)
172 if (rgn->pDimensionRegions[i] == dr)
173 return i;
174 return -1;
175 }
176
177 /// Find the number of bits required to hold the specified amount of zones.
178 inline int zoneCountToBits(int nZones) {
179 if (!nZones) return 0;
180 int iFinalBits = 0;
181 int zoneBits = nZones - 1;
182 for (; zoneBits > 1; iFinalBits += 2, zoneBits >>= 2);
183 iFinalBits += zoneBits;
184 return iFinalBits;
185 }
186
187 /**
188 * Returns the sum of all bits of all dimensions defined before the given
189 * dimensions (@a type). This allows to access cases of that particular
190 * dimension directly. If the supplied dimension @a type does not exist in the
191 * the supplied @a region, then this function returns -1 instead!
192 *
193 * @param type - dimension that shall be used
194 * @param rgn - parent region of that dimension
195 */
196 inline int baseBits(gig::dimension_t type, gig::Region* rgn) {
197 int previousBits = 0;
198 for (uint i = 0; i < rgn->Dimensions; ++i) {
199 if (rgn->pDimensionDefinitions[i].dimension == type) return previousBits;
200 previousBits += rgn->pDimensionDefinitions[i].bits;
201 }
202 return -1;
203 }
204
205 // key: dimension type, value: dimension's zone index
206 class DimensionCase : public std::map<gig::dimension_t,int> {
207 public:
208 bool isViolating(const DimensionCase& c) const {
209 for (DimensionCase::const_iterator it = begin(); it != end(); ++it) {
210 if (c.find(it->first) == c.end()) continue;
211 if (c.find(it->first)->second != it->second) return true;
212 }
213 return false;
214 }
215
216 // prevent passing gig::dimension_none from creating a new pair
217 // (TODO: other invalid gig::dimension_t values should be filtered here as well)
218 int& operator[](const gig::dimension_t& k) {
219 static int unused = 0;
220 if (k == gig::dimension_none) {
221 unused = 0;
222 return unused;
223 }
224 return std::map<gig::dimension_t,int>::operator[](k);
225 }
226 };
227
228 //TODO: this function and caseOfDimRegion() from dimregionchooser.h are duplicates, eliminate either one of them!
229 inline DimensionCase dimensionCaseOf(gig::DimensionRegion* dr) {
230 DimensionCase dimCase;
231 int idr = getDimensionRegionIndex(dr);
232 if (idr < 0) return dimCase;
233 gig::Region* rgn = (gig::Region*)dr->GetParent();
234 int bitpos = 0;
235 for (int d = 0; d < rgn->Dimensions; ++d) {
236 const gig::dimension_def_t& dimdef = rgn->pDimensionDefinitions[d];
237 const int zone = (idr >> bitpos) & ((1 << dimdef.bits) - 1);
238 dimCase[dimdef.dimension] = zone;
239 bitpos += rgn->pDimensionDefinitions[d].bits;
240 }
241 return dimCase;
242 }
243
244 /**
245 * Checks whether the passed dimension zones are within the boundaries of the
246 * defined dimensions. This is especially relevant if there are dimensions
247 * defined with an amount not equal to a power of two, in that case there are
248 * unused dimensions regions which should be ignored.
249 */
250 inline bool isUsedCase(const DimensionCase& c, gig::Region* rgn) {
251 for (int d = 0; d < rgn->Dimensions; ++d) {
252 gig::dimension_t type = rgn->pDimensionDefinitions[d].dimension;
253 if (c.find(type) == c.end()) continue;
254 int zone = c.find(type)->second;
255 if (zone < 0 || zone >= rgn->pDimensionDefinitions[d].zones)
256 return false;
257 }
258 return true;
259 }
260
261 inline std::vector<gig::DimensionRegion*> dimensionRegionsMatching(
262 const DimensionCase& dimCase, gig::Region* rgn, bool skipUnusedZones = false)
263 {
264 std::vector<gig::DimensionRegion*> v;
265 for (int idr = 0; idr < 256; ++idr) {
266 if (!rgn->pDimensionRegions[idr]) continue;
267 DimensionCase c = dimensionCaseOf(rgn->pDimensionRegions[idr]);
268 if (dimCase.isViolating(c)) continue;
269 if (skipUnusedZones && !isUsedCase(c, rgn)) continue;
270 v.push_back(rgn->pDimensionRegions[idr]);
271 }
272 return v;
273 }
274
275 inline gig::DimensionRegion* dimensionRegionMatching(const DimensionCase& dimCase, gig::Region* rgn) {
276 for (int idr = 0; idr < 256; ++idr) {
277 if (!rgn->pDimensionRegions[idr]) continue;
278 DimensionCase c = dimensionCaseOf(rgn->pDimensionRegions[idr]);
279 if (c == dimCase) return rgn->pDimensionRegions[idr];
280 }
281 return NULL;
282 }
283
284 inline std::list<gig::Sample*> unusedSamples(gig::File* file) {
285 std::list<gig::Sample*> lsamples;
286 for (int iSample = 0; file->GetSample(iSample); ++iSample) {
287 gig::Sample* sample = file->GetSample(iSample);
288 bool isUsed = false;
289 for (gig::Instrument* instrument = file->GetFirstInstrument(); instrument;
290 instrument = file->GetNextInstrument())
291 {
292 for (gig::Region* rgn = instrument->GetFirstRegion(); rgn;
293 rgn = instrument->GetNextRegion())
294 {
295 for (int i = 0; i < 256; ++i) {
296 if (!rgn->pDimensionRegions[i]) continue;
297 if (rgn->pDimensionRegions[i]->pSample != sample) continue;
298 isUsed = true;
299 goto endOfRefSearch;
300 }
301 }
302 }
303 endOfRefSearch:
304 if (!isUsed) lsamples.push_back(sample);
305 }
306 return lsamples;
307 }
308
309 inline std::vector<gig::Script*> unusedScripts(gig::File* file) {
310 std::vector<gig::Script*> scripts;
311 for (int iGroup = 0; file->GetScriptGroup(iGroup); ++iGroup) {
312 gig::ScriptGroup* group = file->GetScriptGroup(iGroup);
313 for (int iScript = 0; group->GetScript(iScript); ++iScript) {
314 gig::Script* script = group->GetScript(iScript);
315 bool isUsed = false;
316 for (gig::Instrument* instrument = file->GetFirstInstrument(); instrument;
317 instrument = file->GetNextInstrument())
318 {
319 for (int iSlot = 0; iSlot < instrument->ScriptSlotCount(); ++iSlot)
320 {
321 if (instrument->GetScriptOfSlot(iSlot) == script) {
322 isUsed = true;
323 goto endOfRefSearch;
324 }
325 }
326 }
327 endOfRefSearch:
328 if (!isUsed) scripts.push_back(script);
329 }
330 }
331 return scripts;
332 }
333
334 template<typename T_Message>
335 class SignalGuard {
336 public:
337 SignalGuard(sigc::signal<void, T_Message>& start, sigc::signal<void, T_Message>& end, T_Message message)
338 : m_end(end), m_message(message)
339 {
340 if (message) start.emit(message);
341 }
342
343 virtual ~SignalGuard() {
344 if (m_message) m_end.emit(m_message);
345 }
346 protected:
347 sigc::signal<void, T_Message>& m_end;
348 T_Message m_message;
349 };
350
351 #endif // GIGEDIT_GLOBAL_H

  ViewVC Help
Powered by ViewVC