Imported Upstream version 3.4.2
Dan Stowell
13 years ago
0 | 0 | -*-text-*--------------------------------------------------------------- |
1 | 1 | supercollider 3 for linux |
2 | 2 | ------------------------------------------------------------------------ |
3 | $Id: README LINUX 10144 2010-06-05 07:37:21Z danstowell $ | |
3 | $Id$ | |
4 | 4 | ------------------------------------------------------------------------ |
5 | 5 | |
6 | 6 | ------------------------------------------------------------------------ |
0 | 3.4 | |
1 | classvar scVersionMajor=3, scVersionMinor=4, scVersionPostfix=""; | |
0 | 3.4.2 | |
1 | classvar scVersionMajor=3, scVersionMinor=4, scVersionPostfix=".2"; |
57 | 57 | // Returns TRUE iff 'name' is to be ignored during compilation. |
58 | 58 | bool sc_SkipDirectory(const char *name); |
59 | 59 | |
60 | void sc_ResolveIfAlias(const char *path, char *returnPath, bool &isAlias, int length); | |
60 | int sc_ResolveIfAlias(const char *path, char *returnPath, bool &isAlias, int length); | |
61 | 61 | |
62 | 62 | extern char *gIdeName; // string used for conditional compilation according to which IDE is in use this session. |
63 | 63 | // for example, if the value is "scapp" then folders "scide_scapp" will be included, all other "scide_*" excluded. |
0 | 0 | // emacs: -*- c++ -*- |
1 | 1 | // file: SC_StringBuffer.h |
2 | 2 | // copyright: 2003 stefan kersten <steve@k-hornz.de> |
3 | // cvs: $Id: SC_StringBuffer.h 9082 2009-04-20 08:38:27Z danstowell $ | |
3 | // cvs: $Id$ | |
4 | 4 | |
5 | 5 | // This program is free software; you can redistribute it and/or |
6 | 6 | // modify it under the terms of the GNU General Public License as |
0 | 0 | // emacs: -*- c++ -*- |
1 | 1 | // file: SC_StringParser.h |
2 | 2 | // copyright: 2003-2006 stefan kersten |
3 | // cvs: $Id: SC_StringParser.h 9082 2009-04-20 08:38:27Z danstowell $ | |
3 | // cvs: $Id$ | |
4 | 4 | |
5 | 5 | // This program is free software; you can redistribute it and/or |
6 | 6 | // modify it under the terms of the GNU General Public License as |
75 | 75 | void yyerror(char *s) ; |
76 | 76 | void fatal() ; |
77 | 77 | bool isValidSourceFileName(char *filename); |
78 | bool passOne_ProcessOneFile(char *filename, int level); | |
78 | bool passOne_ProcessOneFile(const char *filename, int level); | |
79 | 79 | |
80 | 80 | extern void asRelativePath(char *inPath,char *outPath); |
81 | 81 |
193 | 193 | inline bool NotFloat(PyrSlot* slot) { return (((slot)->utag & 0xFFFFFFF0) == 0x7FF90000); } |
194 | 194 | |
195 | 195 | inline bool IsPtr(PyrSlot* slot) { return ((slot)->utag == tagPtr); } |
196 | inline bool NotPtr(PyrSlot* slot) { return ((slot)->utag != tagPtr); } | |
196 | 197 | |
197 | 198 | inline void SetRawChar(PyrSlot* slot, int val) { assert(IsChar(slot)); slot->uc = val; } |
198 | 199 | inline void SetRaw(PyrSlot* slot, int val) { assert(IsInt(slot)); slot->ui = val; } |
0 | 0 | // emacs: -*- c++ -*- |
1 | 1 | // file: SC_LibraryConfig.h |
2 | // cvs: $Id: SC_LibraryConfig.h 9417 2009-09-26 06:17:48Z timblech $ | |
2 | // cvs: $Id$ | |
3 | 3 | |
4 | 4 | // This program is free software; you can redistribute it and/or |
5 | 5 | // modify it under the terms of the GNU General Public License as |
31 | 31 | done |
32 | 32 | shift $(($OPTIND - 1)) |
33 | 33 | |
34 | revision=`svnversion -n ../../` | |
35 | if ( echo $revision | grep "M" > /dev/null 2>&1 ); then | |
36 | echo "WARNING: The working copy has uncommitted changes which will be included in the package." | |
34 | revision=`git rev-list HEAD -1 | sed -E 's/([[:alnum:]]{1,10}).*/\1/'` | |
35 | if [ "`git status -s -uno`" != "" ]; then | |
36 | echo "WARNING: The working copy has uncommitted changes which will NOT be included in the package." | |
37 | 37 | fi |
38 | ||
39 | if ( echo $revision | grep ":" > /dev/null 2>&1 ); then | |
40 | echo "WARNING: The working copy has mixed revision numbers (some folders had 'svn update' ran more recently than others)." | |
41 | fi | |
42 | revision=`echo $revision | sed -e 's/^[^:]*://;s/[A-Za-z]//'` | |
43 | 38 | |
44 | 39 | if [ $package_type == "source" ]; then |
45 | 40 | mkdir SuperCollider-Source |
46 | svn export -q --force ../../ SuperCollider-Source | |
41 | returndir=`pwd` | |
42 | cd ../../ | |
43 | git archive $revision | tar -x --exclude ".gitignore" -C "$returndir/SuperCollider-Source" | |
44 | cd $returndir | |
47 | 45 | |
48 | 46 | if $include_optionals; then |
49 | 47 | cp -Rp optional SuperCollider-Source/optional_installs |
56 | 54 | fi |
57 | 55 | |
58 | 56 | # Here we build a list of (many) files that are useless on linux, so as to build a slimline source.tar.gz |
59 | find SuperCollider-Source -iname windows -or -iname osx -or -name "*.xcodeproj" -or -name scide_scapp -or -name "iPhone*" > LinuxExclusions.txt | |
57 | find SuperCollider-Source -iname windows -or -iname osx -or -name "*.xcodeproj" -or -name scide_scapp -or -iname "iPhone*" > LinuxExclusions.txt | |
60 | 58 | echo 'SuperCollider-Source/SuperColliderAU |
61 | 59 | SuperCollider-Source/Psycollider |
62 | 60 | SuperCollider-Source/README OS X |
68 | 66 | SuperCollider-Source/mac |
69 | 67 | SuperCollider-Source/iphone |
70 | 68 | SuperCollider-Source/common/Source/lang/LangPrimSource/HID_Utilities |
69 | SuperCollider-Source/common/Source/lang/LangPrimSource/WiiMote_OSX | |
71 | 70 | SuperCollider-Source/common/Headers/app |
72 | 71 | SuperCollider-Source/common/Source/app' >> LinuxExclusions.txt |
73 | 72 | |
87 | 86 | about_version="$version (Revision $revision)" |
88 | 87 | echo "About box version string:" $about_version |
89 | 88 | |
90 | svn export -q --force ../../common/build SuperCollider | |
91 | cp -R ../../common/build/SuperCollider.app ../../common/build/scsynth ../../common/build/sclang SuperCollider | |
92 | cp ../../common/build/plugins/* SuperCollider/plugins/ | |
93 | cp ../../COPYING SuperCollider/COPYING | |
89 | mkdir -p SuperCollider/plugins | |
90 | returndir=`pwd` | |
91 | cd ../../common/build | |
92 | git archive $revision | tar -x -C "$returndir/SuperCollider" | |
93 | cp -R SuperCollider.app scsynth sclang "$returndir/SuperCollider/" | |
94 | cp plugins/* "$returndir/SuperCollider/plugins/" | |
95 | cp ../../COPYING "$returndir/SuperCollider/" | |
96 | cd $returndir | |
94 | 97 | find SuperCollider/help/ \( -name "*.htm" -or -name "*.html" \) -exec /Developer/Tools/SetFile -c SCjm {} \; |
95 | 98 | defaults write $PWD/SuperCollider/SuperCollider.app/Contents/Info CFBundleVersion -string "$about_version" |
96 | 99 | defaults write $PWD/SuperCollider/SuperCollider.app/Contents/Info CFBundleGetInfoString -string "$version" |
50 | 50 | CPU = short_cpu_name(platform.uname()[4]) |
51 | 51 | |
52 | 52 | ANY_FILE_RE = re.compile('.*') |
53 | HELP_FILE_RE = re.compile('.*\.(rtf(d)?|scd|html)$') | |
53 | HELP_FILE_RE = re.compile('.*\.(rtf(d)?|scd|htm(l)?)$') | |
54 | 54 | SC_FILE_RE = re.compile('.*\.sc$') |
55 | 55 | SRC_FILE_RE = re.compile('.*\.(c(pp)|h)$') |
56 | 56 | |
266 | 266 | def make_static_objects(env, sources, postfix="_a"): |
267 | 267 | return map(lambda x: make_static_object(env, x, postfix), sources) |
268 | 268 | |
269 | # for linking libX.so => libX.so.1 on *nixy systems. Note, they must be in same dir. | |
270 | def make_local_symlink(target, source, env): | |
271 | targetname = os.path.basename(str(target[0])) | |
272 | if os.path.isfile(targetname): | |
273 | if not os.path.islink(targetname): | |
274 | liblog.error("ERROR: cannot create symlink %s because already exists as non-symlink." % (targetname)) | |
275 | else: | |
276 | os.symlink(os.path.basename(str(source[0])), targetname) | |
277 | return None | |
278 | ||
279 | # for linking libX.so => libX.so.1 on *nixy systems. Note, they must be in same dir. | |
280 | def make_local_symlink(target, source, env): | |
281 | targetname = os.path.basename(str(target[0])) | |
282 | if os.path.isfile(targetname): | |
283 | if not os.path.islink(targetname): | |
284 | liblog.error("ERROR: cannot create symlink %s because already exists as non-symlink." % (targetname)) | |
285 | else: | |
286 | os.symlink(os.path.basename(str(source[0])), targetname) | |
287 | return None | |
288 | ||
269 | 289 | # ====================================================================== |
270 | 290 | # command line options |
271 | 291 | # ====================================================================== |
287 | 307 | BoolOption('DEBUG', |
288 | 308 | 'Build with debugging information', 0), |
289 | 309 | PathOption('DESTDIR', |
290 | 'Intermediate installation prefix for packaging', '/'), | |
310 | 'Intermediate installation prefix for packaging', '/', | |
311 | PathOption.PathAccept), | |
291 | 312 | BoolOption('DEVELOPMENT', |
292 | 313 | 'Build and install the development files', 0), |
293 | 314 | BoolOption('FFTW', |
750 | 771 | '#Headers/server'], |
751 | 772 | CPPDEFINES = [('SC_PLUGIN_DIR', '\\"' + pkg_lib_dir(FINAL_PREFIX, 'plugins') + '\\"'), ('SC_PLUGIN_EXT', '\\"' + PLUGIN_EXT + '\\"')], |
752 | 773 | LIBPATH = 'build') |
774 | ||
775 | # platform specific | |
776 | ||
777 | # functionality of libdl is included in libc on freebsd | |
778 | if PLATFORM == 'freebsd': | |
779 | serverEnv.Append(LIBS = ['common', 'pthread']) | |
780 | else: | |
781 | serverEnv.Append(LIBS = ['common', 'pthread', 'dl']) | |
782 | ||
783 | if PLATFORM == 'darwin': | |
784 | serverEnv.Append( | |
785 | LINKFLAGS = [ | |
786 | '-framework', 'CoreServices']) | |
787 | elif PLATFORM == 'linux': | |
788 | serverEnv.Append( | |
789 | CPPDEFINES = [('SC_PLUGIN_LOAD_SYM', '\\"load\\"')], | |
790 | LINKFLAGS = ['-Wl,-rpath,' + FINAL_PREFIX + '/lib']) | |
791 | ||
792 | elif PLATFORM == 'freebsd': | |
793 | serverEnv.Append(CPPDEFINES = [('SC_PLUGIN_LOAD_SYM', '\\"load\\"')]) | |
794 | ||
795 | # required libraries | |
796 | merge_lib_info( | |
797 | serverEnv, | |
798 | libraries['sndfile'], libraries['audioapi']) | |
799 | ||
800 | # optional features | |
801 | if features['rendezvous']: | |
802 | serverEnv.Append(CPPDEFINES = ['USE_RENDEZVOUS']) | |
803 | merge_lib_info(serverEnv, libraries['rendezvous']) | |
804 | ||
805 | if env['CURL']: | |
806 | serverEnv.Append(CPPDEFINES = ['HAVE_LIBCURL']) | |
807 | merge_lib_info(serverEnv, libraries['libcurl']) | |
808 | ||
753 | 809 | libscsynthEnv = serverEnv.Clone( |
754 | 810 | PKGCONFIG_NAME = 'libscsynth', |
755 | 811 | PKGCONFIG_DESC = 'SuperCollider synthesis server library', |
759 | 815 | libraries['rendezvous']), |
760 | 816 | PKGCONFIG_LIBS = ['-lscsynth'], |
761 | 817 | # PKGCONFIG_LIBS_PRIVATE = ['-lm', '-lpthread', '-ldl'], |
762 | PKGCONFIG_CFLAGS = ['-D' + PLATFORM_SYMBOL, '-I${includedir}/common', '-I${includedir}/plugin_interface', '-I${includedir}/server'] | |
818 | PKGCONFIG_CFLAGS = ['-D' + PLATFORM_SYMBOL, '-I${includedir}/common', '-I${includedir}/plugin_interface', '-I${includedir}/server'], | |
819 | SHLIBSUFFIX='.so.1.0.0', | |
820 | LIBSUFFIXES=['.so.1.0.0'] | |
763 | 821 | ) |
764 | ||
765 | # platform specific | |
766 | ||
767 | # functionality of libdl is included in libc on freebsd | |
768 | if PLATFORM == 'freebsd': | |
769 | serverEnv.Append(LIBS = ['common', 'pthread']) | |
770 | else: | |
771 | serverEnv.Append(LIBS = ['common', 'pthread', 'dl']) | |
772 | ||
773 | if PLATFORM == 'darwin': | |
774 | serverEnv.Append( | |
775 | LINKFLAGS = [ | |
776 | '-framework', 'CoreServices']) | |
777 | elif PLATFORM == 'linux': | |
778 | serverEnv.Append( | |
779 | CPPDEFINES = [('SC_PLUGIN_LOAD_SYM', '\\"load\\"')], | |
780 | LINKFLAGS = ['-Wl,-rpath,' + FINAL_PREFIX + '/lib']) | |
781 | ||
782 | elif PLATFORM == 'freebsd': | |
783 | serverEnv.Append(CPPDEFINES = [('SC_PLUGIN_LOAD_SYM', '\\"load\\"')]) | |
784 | ||
785 | # required libraries | |
786 | merge_lib_info( | |
787 | serverEnv, | |
788 | libraries['sndfile'], libraries['audioapi']) | |
789 | ||
790 | # optional features | |
791 | if features['rendezvous']: | |
792 | serverEnv.Append(CPPDEFINES = ['USE_RENDEZVOUS']) | |
793 | merge_lib_info(serverEnv, libraries['rendezvous']) | |
794 | ||
795 | if env['CURL']: | |
796 | serverEnv.Append(CPPDEFINES = ['HAVE_LIBCURL']) | |
797 | merge_lib_info(serverEnv, libraries['libcurl']) | |
822 | if PLATFORM == 'linux': | |
823 | libscsynthEnv.Append( | |
824 | LINKFLAGS = ['-Wl,-soname,libscsynth.so.1.0.0']) | |
825 | # create local symlink for linker to follow (not installed) | |
826 | libscsynthEnv.Command('build/libscsynth.so', 'build/libscsynth.so.1.0.0', make_local_symlink, chdir=1) | |
798 | 827 | |
799 | 828 | libscsynthSources = Split(''' |
800 | 829 | Source/server/Rendezvous.cpp |
823 | 852 | |
824 | 853 | scsynthSources = ['Source/server/scsynth_main.cpp'] |
825 | 854 | |
826 | libscsynth = serverEnv.SharedLibrary('build/scsynth', libscsynthSources) | |
855 | libscsynth = libscsynthEnv.SharedLibrary('build/scsynth', libscsynthSources) | |
827 | 856 | env.Alias('install-programs', env.Install(lib_dir(INSTALL_PREFIX), [libscsynth])) |
857 | env.Alias('install-programs', env.Command(lib_dir(INSTALL_PREFIX) + '/libscsynth.so', lib_dir(INSTALL_PREFIX) + '/libscsynth.so.1.0.0', make_local_symlink, chdir=1)) | |
828 | 858 | |
829 | 859 | libscsynthStaticSources = libscsynthSources + make_static_objects(serverEnv, commonSources, "_libscsynthStatic"); |
830 | 860 | libscsynthStatic = serverEnv.StaticLibrary('build/scsynth', libscsynthStaticSources) |
1032 | 1062 | PKGCONFIG_PREFIX = FINAL_PREFIX, |
1033 | 1063 | PKGCONFIG_REQUIRES = make_pkgconfig_requires(libraries['sndfile']) + ['libscsynth'], |
1034 | 1064 | PKGCONFIG_LIBS = ['-lsclang'], |
1035 | PKGCONFIG_CFLAGS = ['-D' + PLATFORM_SYMBOL, '-I${includedir}/common', '-I${includedir}/plugin_interface', '-I${includedir}/lang', '-I${includedir}/server'] | |
1065 | PKGCONFIG_CFLAGS = ['-D' + PLATFORM_SYMBOL, '-I${includedir}/common', '-I${includedir}/plugin_interface', '-I${includedir}/lang', '-I${includedir}/server'], | |
1066 | SHLIBSUFFIX='.so.1.0.0', | |
1067 | LIBSUFFIXES=['.so.1.0.0'] | |
1036 | 1068 | ) |
1037 | 1069 | if PLATFORM == 'linux': |
1038 | 1070 | libsclangEnv.Append( |
1039 | LINKFLAGS = ['-Wl,-soname,libsclang.so']) | |
1071 | LINKFLAGS = ['-Wl,-soname,libsclang.so.1.0.0']) | |
1072 | # create local symlink for linker to follow (not installed) | |
1073 | libsclangEnv.Command('build/libsclang.so', 'build/libsclang.so.1.0.0', make_local_symlink, chdir=1) | |
1074 | Requires('build/libsclang.so.1.0.0', 'build/libscsynth.so') | |
1040 | 1075 | |
1041 | 1076 | # required libraries |
1042 | 1077 | merge_lib_info(langEnv, libraries['sndfile']) |
1139 | 1174 | sclangSources = ['Source/lang/LangSource/cmdLineFuncs.cpp'] |
1140 | 1175 | |
1141 | 1176 | if env['LANG']: |
1142 | libsclang = langEnv.SharedLibrary('build/sclang', libsclangSources) | |
1177 | libsclang = libsclangEnv.SharedLibrary('build/sclang', libsclangSources) | |
1143 | 1178 | env.Alias('install-bin', env.Install(lib_dir(INSTALL_PREFIX), [libsclang])) |
1179 | env.Alias('install-bin', env.Command(lib_dir(INSTALL_PREFIX) + '/libsclang.so', lib_dir(INSTALL_PREFIX) + '/libsclang.so.1.0.0', make_local_symlink, chdir=1)) | |
1144 | 1180 | if PLATFORM == 'darwin': |
1145 | 1181 | sclangLibs = ['scsynth', 'sclang'] |
1146 | 1182 | else: |
172 | 172 | } |
173 | 173 | |
174 | 174 | |
175 | void sc_ResolveIfAlias(const char *path, char *returnPath, bool &isAlias, int length) | |
175 | int sc_ResolveIfAlias(const char *path, char *returnPath, bool &isAlias, int length) | |
176 | 176 | { |
177 | 177 | isAlias = false; |
178 | #ifdef SC_DARWIN | |
178 | #if defined(__APPLE__) && !defined(SC_IPHONE) | |
179 | 179 | FSRef dirRef; |
180 | 180 | OSStatus osStatusErr = FSPathMakeRef ((const UInt8 *) path, &dirRef, NULL); |
181 | 181 | if ( !osStatusErr ) { |
182 | 182 | Boolean isFolder; |
183 | 183 | Boolean wasAliased; |
184 | 184 | OSErr err = FSResolveAliasFile (&dirRef, true, &isFolder, &wasAliased); |
185 | if (err) | |
186 | { | |
187 | return -1; | |
188 | } | |
185 | 189 | isAlias = wasAliased; |
186 | if ( !err && wasAliased ) { | |
190 | if (wasAliased) | |
191 | { | |
187 | 192 | UInt8 resolvedPath[PATH_MAX]; |
188 | 193 | osStatusErr = FSRefMakePath (&dirRef, resolvedPath, length); |
189 | if ( !osStatusErr ) { | |
190 | strncpy(returnPath, (char *) resolvedPath, length); | |
191 | return; | |
194 | if (osStatusErr) | |
195 | { | |
196 | return -1; | |
192 | 197 | } |
198 | strncpy(returnPath, (char *) resolvedPath, length); | |
199 | return 0; | |
193 | 200 | } |
194 | 201 | } |
195 | #elif defined(SC_LINUX) | |
202 | #elif defined(__linux__) || defined(__FreeBSD__) | |
196 | 203 | isAlias = sc_IsSymlink(path); |
197 | if (!realpath(path, returnPath)) | |
198 | strcpy(returnPath, path); | |
199 | return; | |
200 | #elif defined(SC_FREEBSD) | |
201 | isAlias = sc_IsSymlink(path); | |
202 | if (!realpath(path, returnPath)) | |
203 | strcpy(returnPath, path); | |
204 | return; | |
204 | if (realpath(path, returnPath)) | |
205 | { | |
206 | return 0; | |
207 | } | |
208 | ||
209 | return -1; | |
205 | 210 | #endif |
206 | 211 | strcpy(returnPath, path); |
207 | return; | |
212 | return 0; | |
208 | 213 | } |
209 | 214 | |
210 | 215 | // Support for Bundles |
543 | 548 | char* errstr = (char*)malloc(CURL_ERROR_SIZE); |
544 | 549 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errstr); |
545 | 550 | if((ret = curl_easy_setopt(curl, CURLOPT_URL, mFilename)) != 0){ |
546 | scprintf("CURL setopt error while setting URL. Error code %i\n%s\n", ret, errstr); | |
551 | printf("CURL setopt error while setting URL. Error code %i\n%s\n", ret, errstr); | |
547 | 552 | success = false; |
548 | 553 | } |
549 | 554 | if((ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp)) != 0){ |
550 | scprintf("CURL setopt error while setting temp file pointer. Error code %i\n%s\n", ret, errstr); | |
555 | printf("CURL setopt error while setting temp file pointer. Error code %i\n%s\n", ret, errstr); | |
551 | 556 | success = false; |
552 | 557 | } |
553 | 558 | //printf("Loading remote file %s...\n", mFilename); |
554 | 559 | if((ret = curl_easy_perform(curl)) != 0){ |
555 | scprintf("CURL perform error while attempting to access remote file. Error code %i\n%s\n", ret, errstr); | |
560 | printf("CURL perform error while attempting to access remote file. Error code %i\n%s\n", ret, errstr); | |
556 | 561 | success = false; |
557 | 562 | //}else{ |
558 | 563 | // printf("...done.\n"); |
0 | 0 | // emacs: -*- c++ -*- |
1 | 1 | // file: SC_StringBuffer.cpp |
2 | 2 | // copyright: 2003 stefan kersten <steve@k-hornz.de> |
3 | // cvs: $Id: SC_StringBuffer.cpp 9082 2009-04-20 08:38:27Z danstowell $ | |
3 | // cvs: $Id$ | |
4 | 4 | |
5 | 5 | // This program is free software; you can redistribute it and/or |
6 | 6 | // modify it under the terms of the GNU General Public License as |
33 | 33 | { |
34 | 34 | toaddr.sin_family = AF_INET; // host byte order |
35 | 35 | toaddr.sin_port = htons(port); // short, network byte order |
36 | addr = htonl(addr); | |
37 | toaddr.sin_addr = *((struct in_addr *)&addr); | |
36 | toaddr.sin_addr.s_addr = htonl(addr); | |
38 | 37 | bzero(&(toaddr.sin_zero), 8); // zero the rest of the struct |
39 | 38 | } |
40 | 39 |
1781 | 1781 | int newSize = 1; |
1782 | 1782 | int tupSize = obj1->size; |
1783 | 1783 | for (int i=0; i < tupSize; ++i) { |
1784 | if (isKindOfSlot(slots1+i, class_arrayed_collection)) { | |
1784 | if (isKindOfSlot(slots1+i, class_array)) { | |
1785 | 1785 | newSize *= slotRawObject(&slots1[i])->size; |
1786 | 1786 | } |
1787 | 1787 | } |
1792 | 1792 | |
1793 | 1793 | for (int i=0; i < newSize; ++i) { |
1794 | 1794 | int k = i; |
1795 | obj3 = (PyrObject*)instantiateObject(g->gc, obj1->classptr, tupSize, false, true); | |
1795 | obj3 = (PyrObject*)instantiateObject(g->gc, obj1->classptr, tupSize, false, false); | |
1796 | 1796 | slots3 = obj3->slots; |
1797 | 1797 | for (int j=tupSize-1; j >= 0; --j) { |
1798 | if (isKindOfSlot(slots1+j, class_arrayed_collection)) { | |
1798 | if (isKindOfSlot(slots1+j, class_array)) { | |
1799 | 1799 | PyrObject *obj4 = slotRawObject(&slots1[j]); |
1800 | 1800 | slotCopy(&slots3[j],&obj4->slots[k % obj4->size]); |
1801 | g->gc->GCWrite(obj3, obj3); | |
1801 | g->gc->GCWrite(obj3, obj4); | |
1802 | 1802 | k /= obj4->size; |
1803 | 1803 | } else { |
1804 | 1804 | slotCopy(&slots3[j],&slots1[j]); |
2335 | 2335 | if(size3 < 1) return errFailed; |
2336 | 2336 | |
2337 | 2337 | for(i=0; i<numLists; ++i) { |
2338 | obj3 = (PyrObject*)instantiateObject(g->gc, obj1->classptr, size3, false, true); | |
2338 | obj3 = (PyrObject*)instantiateObject(g->gc, obj1->classptr, size3, false, false); | |
2339 | 2339 | obj3->size = size3; |
2340 | 2340 | slots3 = obj3->slots; |
2341 | 2341 | for(j=0; j<size3; j+=clump) { |
2980 | 2980 | |
2981 | 2981 | err = slotIntVal(c, &stacksize); |
2982 | 2982 | if (err) return err; |
2983 | ||
2984 | stacksize = std::max(stacksize, EVALSTACKDEPTH); | |
2983 | 2985 | |
2984 | 2986 | initPyrThread(g, thread, b, stacksize, (PyrInt32Array*)(slotRawObject(&g->thread->randData)), |
2985 | 2987 | slotRawFloat(&g->thread->beats), slotRawFloat(&g->thread->seconds), &g->thread->clock, true); |
1118 | 1118 | err = slotDoubleVal(b, &delta); |
1119 | 1119 | if (err) return errNone; // return nil OK, just don't schedule |
1120 | 1120 | beats += delta; |
1121 | if(beats == INFINITY) return errNone; // return nil OK, just don't schedule | |
1121 | 1122 | |
1122 | 1123 | clock->Add(beats, c); |
1123 | 1124 | |
1138 | 1139 | } |
1139 | 1140 | |
1140 | 1141 | double beats; |
1141 | int err = slotDoubleVal(b, &beats); | |
1142 | int err = slotDoubleVal(b, &beats) || (beats == INFINITY); | |
1142 | 1143 | if (err) return errNone; // return nil OK, just don't schedule |
1143 | 1144 | |
1144 | 1145 | clock->Add(beats, c); |
1297 | 1298 | err = slotDoubleVal(&g->thread->seconds, &seconds); |
1298 | 1299 | if (err) return errNone; // return nil OK, just don't schedule |
1299 | 1300 | seconds += delta; |
1301 | if(seconds == INFINITY) return errNone; // return nil OK, just don't schedule | |
1300 | 1302 | PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); |
1301 | 1303 | |
1302 | 1304 | schedAdd(g, inQueue, seconds, c); |
1312 | 1314 | PyrSlot *c = g->sp; |
1313 | 1315 | |
1314 | 1316 | double time; |
1315 | int err = slotDoubleVal(b, &time); | |
1317 | int err = slotDoubleVal(b, &time) || (time == INFINITY); | |
1316 | 1318 | if (err) return errNone; // return nil OK, just don't schedule |
1317 | 1319 | PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); |
1318 | 1320 |
512 | 512 | |
513 | 513 | static SerialPort* getSerialPort(PyrSlot* slot) |
514 | 514 | { |
515 | if (NotPtr(&slotRawObject(slot)->slots[0])) | |
516 | return NULL; | |
515 | 517 | return (SerialPort*)slotRawPtr(&slotRawObject(slot)->slots[0]); |
516 | 518 | } |
517 | 519 |
48 | 48 | }; |
49 | 49 | typedef struct SCRegExRegion SCRegExRegion; |
50 | 50 | |
51 | int prString_FindRegexp(struct VMGlobals *g, int numArgsPushed); | |
52 | int prString_FindRegexp(struct VMGlobals *g, int numArgsPushed) | |
51 | static int prString_FindRegexp(struct VMGlobals *g, int numArgsPushed) | |
53 | 52 | { |
54 | int err; | |
55 | ||
56 | 53 | PyrSlot *a = g->sp - 2; // source string |
57 | 54 | PyrSlot *b = g->sp - 1; // pattern |
58 | 55 | PyrSlot *c = g->sp; // offset |
64 | 61 | int stringsize = slotRawObject(a)->size + 1; |
65 | 62 | int patternsize = slotRawObject(b)->size + 1; |
66 | 63 | char *string = (char*)malloc(slotRawObject(a)->size + 1); |
67 | err = slotStrVal(a, string, slotRawObject(a)->size + 1); | |
64 | int err = slotStrVal(a, string, slotRawObject(a)->size + 1); | |
68 | 65 | if (err){ |
69 | 66 | free(string); |
70 | 67 | return err; |
133 | 130 | { |
134 | 131 | result_array->size++; |
135 | 132 | SetNil(result_array->slots+i); |
136 | } | |
137 | else | |
138 | { | |
139 | result_array->size++; | |
140 | ||
133 | } else { | |
141 | 134 | int match_start = what[i].start; |
142 | 135 | int match_length = what[i].end - what[i].start; |
143 | 136 | // post("for i:%i, start %i, end %i\n", i, what[i].start, what[i].end); |
144 | // char *match = (char*)malloc(match_length); | |
145 | char match[match_length]; | |
137 | char match[match_length+1]; | |
146 | 138 | |
147 | 139 | strncpy(match, string + offset + match_start, match_length); |
148 | 140 | match[match_length] = 0; |
149 | 141 | PyrObject *array = newPyrArray(g->gc, 2, 0, true); |
142 | ||
143 | result_array->size++; | |
144 | SetObject(result_array->slots + i, array); | |
145 | g->gc->GCWrite(result_array, array); | |
146 | ||
147 | PyrObject *matched_string = (PyrObject*)newPyrString(g->gc, match, 0, true); | |
148 | ||
150 | 149 | array->size = 2; |
151 | 150 | SetInt(array->slots, match_start + offset); |
152 | 151 | |
153 | PyrObject *matched_string = (PyrObject*)newPyrString(g->gc, match, 0, true); | |
154 | 152 | SetObject(array->slots+1, matched_string); |
155 | g->gc->GCWrite(matched_string, array->slots + 1); | |
153 | g->gc->GCWrite(array, matched_string); | |
156 | 154 | |
157 | SetObject(result_array->slots + i, array); | |
158 | g->gc->GCWrite(array, result_array->slots + i); | |
159 | 155 | } |
160 | 156 | } |
161 | 157 | } |
162 | 158 | else |
163 | { | |
164 | 159 | SetNil(a); |
165 | } | |
166 | free(what); | |
167 | free(pattern); | |
168 | free(regexStr); | |
169 | free(ustring); | |
170 | free(string); | |
160 | ||
161 | free(what); | |
162 | free(pattern); | |
163 | free(regexStr); | |
164 | free(ustring); | |
165 | free(string); | |
171 | 166 | SetObject(a, result_array); |
172 | g->gc->GCWrite(result_array,a); | |
173 | 167 | //uregex_close(expression); |
174 | 168 | return errNone; |
175 | 169 | } |
176 | 170 | |
177 | nilout: | |
178 | free(string); | |
179 | free(what); | |
180 | free(pattern); | |
181 | free(regexStr); | |
182 | free(ustring); | |
183 | SetNil(a); | |
184 | return errNone; | |
171 | nilout: | |
172 | free(string); | |
173 | free(what); | |
174 | free(pattern); | |
175 | free(regexStr); | |
176 | free(ustring); | |
177 | SetNil(a); | |
178 | return errNone; | |
185 | 179 | } |
186 | 180 | |
187 | 181 | void initUStringPrimitives(); |
0 | Max porting by Masayuki Akamatsu | |
1 | Copyright (c) 2006, Masayuki Akamatsu | |
2 | Based on "DarwiinRemote" by Hiroaki Kimura | |
3 | Copyright (c) 2006, Hiroaki Kimura | |
4 | All rights reserved. | |
5 | ||
6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | |
7 | ||
8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | |
9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | |
10 | 3. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | |
11 | ||
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.⏎ |
0 | aka.wiiremote Version History | |
1 | ||
2 | 1.0B6 : 2007.04.24 | |
3 | ||
4 | - The Classic Controller is supported. | |
5 | - The help patch is updated. | |
6 | - The URLs in [info] subpatch are updated. | |
7 | ||
8 | - 'expansion' message enables to use the expansion controller(Nunchuk or Classic Controller). | |
9 | - 'nunchuk' message is obsolete. | |
10 | You should use 'expansion' instead of it even though you can use it for the backward compatibility only. | |
11 | ||
12 | - The IR sensor and the expansion controller (ex. Nunchuk) can be used together. | |
13 | ||
14 | - The stability on PPC-Mac is a little improved. | |
15 | You have to do the following steps every time you use the Wii Remote on PPC-Mac. | |
16 | (You would set up only once on Intel-Mac.) | |
17 | 1: Delete "Nintendo RVL-CNT-01" on "Device" tab in "Bluetooth" System Preference. | |
18 | 2: Do the setup for Wii Remote. See http://max.iamas.ac.jp/2061/articles/121.html | |
19 | 3: Open "aka.wiiremote.help" and connect it. | |
20 | ||
21 | ||
22 | 1.0B5 : 2007.02.03 | |
23 | ||
24 | - Nunchuk is supported. | |
25 | ( Classic Controller is NOT supported.) | |
26 | - device address is supported. | |
27 | - outlets and output messages are changed. | |
28 | - some input messages are simplified. | |
29 | - help patch is expanded for Nunchuk. | |
30 | ||
31 | ||
32 | 1.0B4 : 2006.12.24 | |
33 | ||
34 | - multiple Wii remotes are supported. | |
35 | ||
36 | ||
37 | 1.0B3 : 2006.12.20 | |
38 | ||
39 | - data acquisition is improved. | |
40 | - unusual vibration sound is resolved. | |
41 | ||
42 | ||
43 | 1.0B2 : 2006.12.15 | |
44 | ||
45 | - connection/disconnection is improved. | |
46 | - IR sensor is supported. | |
47 | - status report is supported | |
48 | - help patch is rewritten. | |
49 | ||
50 | ||
51 | 1.0B1 : 2006.12.12 | |
52 | ||
53 | - first release⏎ |
0 | // wiiremote.c | |
1 | // Copyright by Masayuki Akamatsu | |
2 | // Based on "DarwiinRemote" by Hiroaki Kimura | |
3 | ||
4 | #include <unistd.h> | |
5 | #include "wiiremote.h" | |
6 | ||
7 | ||
8 | // this type is used a lot (data array): | |
9 | typedef unsigned char darr[]; | |
10 | ||
11 | #define kTrial 10 | |
12 | #define kWait 10000 | |
13 | // the unit of kWait is microseconds, thus 10000 means 10ms | |
14 | ||
15 | #define kWiiIRPixelsWidth 1024.0 | |
16 | #define kWiiIRPixelsHeight 768.0 | |
17 | ||
18 | ||
19 | Boolean requestUpdates(WiiRemoteRef wiiremote); | |
20 | void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event); | |
21 | ||
22 | ||
23 | //-------------------------------------------------------------------------------------------- | |
24 | //-------------------------------------------------------------------------------------------- | |
25 | ||
26 | void wiiremote_init(WiiRemoteRef wiiremote) | |
27 | { | |
28 | wiiremote->inquiry = nil; | |
29 | wiiremote->device = nil; | |
30 | wiiremote->ichan = nil; | |
31 | wiiremote->cchan = nil; | |
32 | ||
33 | wiiremote->address = nil; | |
34 | ||
35 | wiiremote->accX = 0x10; | |
36 | wiiremote->accY = 0x10; | |
37 | wiiremote->accZ = 0x10; | |
38 | wiiremote->buttonData = 0; | |
39 | ||
40 | wiiremote->lowZ = 0; | |
41 | wiiremote->lowX = 0; | |
42 | wiiremote->leftPoint = -1; | |
43 | wiiremote->tracking = false; | |
44 | ||
45 | wiiremote->batteryLevel = 0; | |
46 | ||
47 | wiiremote->readingRegister = false; | |
48 | wiiremote->isMotionSensorEnabled = false; | |
49 | wiiremote->isVibrationEnabled = false; | |
50 | wiiremote->isIRSensorEnabled = false; | |
51 | wiiremote->wiiIRMode = kWiiIRModeExtended; | |
52 | wiiremote->isExpansionPortEnabled = false; | |
53 | wiiremote->isExpansionPortAttached = false; | |
54 | wiiremote->expType = WiiExpNotAttached; | |
55 | ||
56 | wiiremote->isLED1Illuminated = false; | |
57 | wiiremote->isLED2Illuminated = false; | |
58 | wiiremote->isLED3Illuminated = false; | |
59 | wiiremote->isLED4Illuminated = false; | |
60 | ||
61 | wiiremote->nAccX = 0x10; | |
62 | wiiremote->nAccY = 0x10; | |
63 | wiiremote->nAccZ = 0x10; | |
64 | wiiremote->nButtonData = 0; | |
65 | ||
66 | wiiremote->nLowZ = 0; | |
67 | wiiremote->nLowX = 0; | |
68 | ||
69 | } | |
70 | ||
71 | //-------------------------------------------------------------------------------------------- | |
72 | //-------------------------------------------------------------------------------------------- | |
73 | ||
74 | Boolean openCChan(WiiRemoteRef wiiremote) | |
75 | { | |
76 | short i; | |
77 | IOReturn ret; | |
78 | ||
79 | // open L2CAPChannel : BluetoothL2CAPPSM = 17 | |
80 | for (i=0; i<kTrial; i++) | |
81 | { | |
82 | ret = IOBluetoothDeviceOpenL2CAPChannelSync(wiiremote->device, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); | |
83 | if ( ret == kIOReturnSuccess) | |
84 | break; | |
85 | usleep(kWait); // wait 10ms | |
86 | } | |
87 | if (i==kTrial) | |
88 | { | |
89 | wiiremote->cchan = nil; | |
90 | IOBluetoothDeviceCloseConnection(wiiremote->device); | |
91 | return false; | |
92 | } | |
93 | IOBluetoothObjectRetain(wiiremote->cchan); | |
94 | ||
95 | return (ret==kIOReturnSuccess); | |
96 | } | |
97 | ||
98 | Boolean openIChan(WiiRemoteRef wiiremote) | |
99 | { | |
100 | short i; | |
101 | IOReturn ret; | |
102 | ||
103 | // open L2CAPChannel : BluetoothL2CAPPSM = 19 | |
104 | for (i=0; i<kTrial; i++) | |
105 | { | |
106 | ret = IOBluetoothDeviceOpenL2CAPChannelSync(wiiremote->device, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); | |
107 | if ( ret == kIOReturnSuccess) | |
108 | break; | |
109 | usleep(kWait); // wait 10ms | |
110 | } | |
111 | if (i==kTrial) | |
112 | { | |
113 | wiiremote->ichan = nil; | |
114 | IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); | |
115 | IOBluetoothObjectRelease(wiiremote->cchan); | |
116 | IOBluetoothDeviceCloseConnection(wiiremote->device); | |
117 | return false; | |
118 | } | |
119 | IOBluetoothObjectRetain(wiiremote->ichan); | |
120 | ||
121 | return (ret==kIOReturnSuccess); | |
122 | } | |
123 | ||
124 | //-------------------------------------------------------------------------------------------- | |
125 | ||
126 | Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, unsigned short length) | |
127 | { | |
128 | unsigned char buf[40]; | |
129 | IOReturn ret; | |
130 | int i; | |
131 | ||
132 | memset(buf,0,40); | |
133 | buf[0] = 0x52; | |
134 | memcpy(buf+1, data, length); | |
135 | if (buf[1] == 0x16) | |
136 | length=23; | |
137 | else | |
138 | length++; | |
139 | ||
140 | usleep(kWait); // wait 10ms // Done to make sure commands don't happen too fast. | |
141 | ||
142 | for (i = 0; i<kTrial; i++) | |
143 | { | |
144 | ret = IOBluetoothL2CAPChannelWriteSync(wiiremote->cchan, buf, length); | |
145 | if (ret == kIOReturnSuccess) | |
146 | break; | |
147 | usleep(kWait); | |
148 | } | |
149 | ||
150 | if (ret != kIOReturnSuccess) | |
151 | wiiremote_disconnect(wiiremote); | |
152 | ||
153 | return (ret==kIOReturnSuccess); | |
154 | } | |
155 | ||
156 | Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, unsigned short length) | |
157 | { | |
158 | unsigned char cmd[22]; | |
159 | int i; | |
160 | unsigned long addr = address; | |
161 | ||
162 | ||
163 | for(i=0 ; i<length ; i++) | |
164 | cmd[i+6] = data[i]; | |
165 | ||
166 | for(;i<16 ; i++) | |
167 | cmd[i+6]= 0; | |
168 | ||
169 | cmd[0] = 0x16; | |
170 | cmd[1] = (addr>>24) & 0xFF; | |
171 | cmd[2] = (addr>>16) & 0xFF; | |
172 | cmd[3] = (addr>> 8) & 0xFF; | |
173 | cmd[4] = (addr>> 0) & 0xFF; | |
174 | cmd[5] = length; | |
175 | ||
176 | // and of course the vibration flag, as usual | |
177 | if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; | |
178 | ||
179 | data = cmd; | |
180 | ||
181 | return sendCommand(wiiremote, cmd, 22); | |
182 | } | |
183 | ||
184 | Boolean readData(WiiRemoteRef wiiremote, unsigned long address, unsigned short length) | |
185 | { | |
186 | ||
187 | unsigned char cmd[7]; | |
188 | unsigned long addr = address; | |
189 | unsigned short len = length; | |
190 | ||
191 | cmd[0] = 0x17; | |
192 | cmd[1] = (addr>>24)&0xFF; | |
193 | cmd[2] = (addr>>16)&0xFF; | |
194 | cmd[3] = (addr>> 8)&0xFF; | |
195 | cmd[4] = (addr>> 0)&0xFF; | |
196 | ||
197 | cmd[5] = (len >> 8)&0xFF; | |
198 | cmd[6] = (len >> 0)&0xFF; | |
199 | ||
200 | if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; | |
201 | if (cmd[1] & 0x02) wiiremote->readingRegister = true; | |
202 | ||
203 | return sendCommand(wiiremote, cmd, 7); | |
204 | } | |
205 | ||
206 | //-------------------------------------------------------------------------------------------- | |
207 | //-------------------------------------------------------------------------------------------- | |
208 | ||
209 | void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) | |
210 | { | |
211 | CFStringRef name; | |
212 | CFStringRef address; | |
213 | ||
214 | if (wiiremote_isconnected(wiiremote)) | |
215 | return; | |
216 | ||
217 | name = IOBluetoothDeviceGetName(device); | |
218 | address = IOBluetoothDeviceGetAddressString(device); | |
219 | if (name != nil && address != nil) | |
220 | { | |
221 | if (CFStringCompare(name, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) | |
222 | { | |
223 | if ( CFStringGetLength(wiiremote->address) == 0 | |
224 | || CFStringCompare(address, wiiremote->address, kCFCompareCaseInsensitive) == kCFCompareEqualTo) | |
225 | { | |
226 | wiiremote->device = IOBluetoothObjectRetain(device); | |
227 | if ( wiiremote_connect(wiiremote) == false ) | |
228 | wiiremote_disconnect(wiiremote); | |
229 | } | |
230 | } | |
231 | } | |
232 | } | |
233 | ||
234 | void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) | |
235 | { | |
236 | checkDevice((WiiRemoteRef)refCon, device); | |
237 | } | |
238 | ||
239 | void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) | |
240 | { | |
241 | checkDevice((WiiRemoteRef)refCon, device); | |
242 | } | |
243 | ||
244 | void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) | |
245 | { | |
246 | IOReturn ret; | |
247 | ||
248 | if (aborted) return; // called by stop ;) | |
249 | ||
250 | if (error != kIOReturnSuccess) | |
251 | { | |
252 | wiiremote_stopsearch((WiiRemoteRef)refCon); | |
253 | return; | |
254 | } | |
255 | ||
256 | /* | |
257 | ret = IOBluetoothDeviceInquiryStart(((WiiRemoteRef)refCon)->inquiry); | |
258 | if (ret != kIOReturnSuccess) | |
259 | { | |
260 | wiiremote_stopsearch((WiiRemoteRef)refCon); | |
261 | } | |
262 | */ | |
263 | } | |
264 | ||
265 | //-------------------------------------------------------------------------------------------- | |
266 | ||
267 | Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) | |
268 | { | |
269 | Boolean result; | |
270 | ||
271 | result = wiiremote->device != nil && IOBluetoothDeviceIsConnected(wiiremote->device); | |
272 | return result; | |
273 | } | |
274 | ||
275 | Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) | |
276 | { | |
277 | IOReturn ret; | |
278 | ||
279 | if (wiiremote->inquiry != nil) | |
280 | return true; | |
281 | ||
282 | wiiremote->inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon((void *)wiiremote); | |
283 | IOBluetoothDeviceInquirySetDeviceFoundCallback(wiiremote->inquiry, myFoundFunc); | |
284 | IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(wiiremote->inquiry, myUpdatedFunc); | |
285 | IOBluetoothDeviceInquirySetCompleteCallback(wiiremote->inquiry, myCompleteFunc); | |
286 | ||
287 | if (wiiremote->address != nil) | |
288 | CFRelease(wiiremote->address); | |
289 | wiiremote->address = CFStringCreateWithCString(nil, address, kCFStringEncodingMacRoman); | |
290 | ||
291 | ret = IOBluetoothDeviceInquiryStart(wiiremote->inquiry); | |
292 | if (ret != kIOReturnSuccess) | |
293 | { | |
294 | IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); | |
295 | wiiremote->inquiry = nil; | |
296 | return false; | |
297 | } | |
298 | return true; | |
299 | } | |
300 | ||
301 | Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) | |
302 | { | |
303 | IOReturn ret; | |
304 | ||
305 | if (wiiremote->inquiry == nil) | |
306 | { | |
307 | return true; // already stopped | |
308 | } | |
309 | ||
310 | ret = IOBluetoothDeviceInquiryStop(wiiremote->inquiry); | |
311 | ||
312 | if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted) | |
313 | { | |
314 | // kIOReturnNotPermitted is if it's already stopped | |
315 | } | |
316 | ||
317 | IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); | |
318 | wiiremote->inquiry = nil; | |
319 | ||
320 | return (ret==kIOReturnSuccess); | |
321 | } | |
322 | ||
323 | //-------------------------------------------------------------------------------------------- | |
324 | //-------------------------------------------------------------------------------------------- | |
325 | ||
326 | unsigned char decrypt(unsigned char data) | |
327 | { | |
328 | return (data ^ 0x17) + 0x17; | |
329 | } | |
330 | ||
331 | //-------------------------------------------------------------------------------------------- | |
332 | ||
333 | /** | |
334 | * Handle report 0x21 (Read Data) from wiimote. | |
335 | * dp[0] = Bluetooth header | |
336 | * dp[1] = (0x21) Report/Channel ID | |
337 | * dp[2] = Wiimote Buttons | |
338 | * dp[3] = Wiimote Buttons | |
339 | * dp[4] = High 4 bits = payload size; Low 4 bits = Error flag (0 = all good) | |
340 | * dp[5] = Offset of memory read | |
341 | * dp[6] = Offset of memory read | |
342 | * dp[7+] = the Data. | |
343 | **/ | |
344 | ||
345 | void handleRAMData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) | |
346 | { | |
347 | // specify attached expasion device | |
348 | if ((dp[5] == 0x00) && (dp[6] == 0xF0)) | |
349 | { | |
350 | if (decrypt(dp[21]) == 0x00) | |
351 | { | |
352 | wiiremote->expType = WiiNunchuk; | |
353 | } | |
354 | else | |
355 | if (decrypt(dp[21]) == 0x01) | |
356 | { | |
357 | wiiremote->expType = WiiClassicController; | |
358 | } | |
359 | else | |
360 | { | |
361 | wiiremote->expType = WiiExpNotAttached; | |
362 | } | |
363 | // initExpPort = NO; | |
364 | return; | |
365 | } | |
366 | ||
367 | // wiimote calibration data | |
368 | if (!wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) | |
369 | { | |
370 | wiiremote->wiiCalibData.accX_zero = dp[7]; | |
371 | wiiremote->wiiCalibData.accY_zero = dp[8]; | |
372 | wiiremote->wiiCalibData.accZ_zero = dp[9]; | |
373 | ||
374 | //dp[10] - unknown/unused | |
375 | ||
376 | wiiremote->wiiCalibData.accX_1g = dp[11]; | |
377 | wiiremote->wiiCalibData.accY_1g = dp[12]; | |
378 | wiiremote->wiiCalibData.accZ_1g = dp[13]; | |
379 | return; | |
380 | } | |
381 | ||
382 | // expansion device calibration data. | |
383 | if (wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) | |
384 | { | |
385 | if (wiiremote->expType == WiiNunchuk) | |
386 | { | |
387 | //nunchuk calibration data | |
388 | wiiremote->nunchukCalibData.accX_zero = decrypt(dp[7]); | |
389 | wiiremote->nunchukCalibData.accY_zero = decrypt(dp[8]); | |
390 | wiiremote->nunchukCalibData.accZ_zero = decrypt(dp[9]); | |
391 | ||
392 | wiiremote->nunchukCalibData.accX_1g = decrypt(dp[11]); | |
393 | wiiremote->nunchukCalibData.accY_1g = decrypt(dp[12]); | |
394 | wiiremote->nunchukCalibData.accZ_1g = decrypt(dp[13]); | |
395 | ||
396 | wiiremote->nunchukJoyStickCalibData.x_max = decrypt(dp[15]); | |
397 | wiiremote->nunchukJoyStickCalibData.x_min = decrypt(dp[16]); | |
398 | wiiremote->nunchukJoyStickCalibData.x_center = decrypt(dp[17]); | |
399 | ||
400 | wiiremote->nunchukJoyStickCalibData.y_max = decrypt(dp[18]); | |
401 | wiiremote->nunchukJoyStickCalibData.y_min = decrypt(dp[19]); | |
402 | wiiremote->nunchukJoyStickCalibData.y_center = decrypt(dp[20]); | |
403 | ||
404 | return; | |
405 | } | |
406 | else | |
407 | if (wiiremote->expType == WiiClassicController) | |
408 | { | |
409 | //classic controller calibration data (probably) | |
410 | } | |
411 | } | |
412 | ||
413 | // wii remote buttons | |
414 | wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; | |
415 | } | |
416 | ||
417 | void handleStatusReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) | |
418 | { | |
419 | wiiremote->batteryLevel = (double)dp[7]; | |
420 | wiiremote->batteryLevel /= (double)0xC0; // C0 = fully charged. | |
421 | ||
422 | if ((dp[4] & 0x02)) //some device attached to Wiimote | |
423 | { | |
424 | wiiremote->isExpansionPortAttached = true; | |
425 | // initExpPort = YES; | |
426 | ||
427 | Boolean ret = writeData(wiiremote, (darr){0x00}, 0x04A40040, 1); // Initialize the device | |
428 | ||
429 | if (ret == false) | |
430 | { | |
431 | wiiremote->isExpansionPortAttached = false; | |
432 | return; | |
433 | } | |
434 | ||
435 | usleep(kWait); // Give the write a chance to be processed. | |
436 | ||
437 | ret = readData(wiiremote, 0x04A400F0, 16); // read expansion device type | |
438 | if (ret == false) | |
439 | { | |
440 | wiiremote->isExpansionPortAttached = false; | |
441 | } | |
442 | } | |
443 | else | |
444 | { // unplugged | |
445 | wiiremote->isExpansionPortAttached = false; | |
446 | wiiremote->expType = WiiExpNotAttached; | |
447 | } | |
448 | ||
449 | if (dp[4] & 0x10) | |
450 | wiiremote->isLED1Illuminated = true; | |
451 | else | |
452 | wiiremote->isLED1Illuminated = false; | |
453 | ||
454 | if (dp[4] & 0x20) | |
455 | wiiremote->isLED2Illuminated = true; | |
456 | else | |
457 | wiiremote->isLED2Illuminated = false; | |
458 | ||
459 | if (dp[4] & 0x40) | |
460 | wiiremote->isLED3Illuminated = true; | |
461 | else | |
462 | wiiremote->isLED3Illuminated = false; | |
463 | ||
464 | if (dp[4] & 0x80) | |
465 | wiiremote->isLED4Illuminated = true; | |
466 | else | |
467 | wiiremote->isLED4Illuminated = false; | |
468 | } | |
469 | ||
470 | void handleExtensionData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) | |
471 | { | |
472 | unsigned char startByte; | |
473 | ||
474 | switch (dp[1]) { | |
475 | case 0x34 : | |
476 | startByte = 4; | |
477 | break; | |
478 | case 0x35 : | |
479 | startByte = 7; | |
480 | break; | |
481 | case 0x36 : | |
482 | startByte = 14; | |
483 | break; | |
484 | case 0x37 : | |
485 | startByte = 17; | |
486 | break; | |
487 | default: | |
488 | return; // This shouldn't ever happen. | |
489 | break; | |
490 | } | |
491 | ||
492 | if (wiiremote->expType == WiiNunchuk) | |
493 | { | |
494 | wiiremote->nStickX = decrypt(dp[startByte]); | |
495 | wiiremote->nStickY = decrypt(dp[startByte +1]); | |
496 | wiiremote->nAccX = decrypt(dp[startByte +2]); | |
497 | wiiremote->nAccY = decrypt(dp[startByte +3]); | |
498 | wiiremote->nAccZ = decrypt(dp[startByte +4]); | |
499 | wiiremote->nButtonData = decrypt(dp[startByte +5]); | |
500 | ||
501 | wiiremote->nLowZ = wiiremote->nLowZ * .9 + wiiremote->nAccZ * .1; | |
502 | wiiremote->nLowX = wiiremote->nLowX * .9 + wiiremote->nAccX * .1; | |
503 | ||
504 | float absx = abs(wiiremote->nLowX - 128); | |
505 | float absz = abs(wiiremote->nLowZ - 128); | |
506 | ||
507 | if (wiiremote->nOrientation == 0 || wiiremote->nOrientation == 2) absx -= 5; | |
508 | if (wiiremote->nOrientation == 1 || wiiremote->nOrientation == 3) absz -= 5; | |
509 | ||
510 | if (absz >= absx) | |
511 | { | |
512 | if (absz > 5) | |
513 | wiiremote->nOrientation = (wiiremote->nLowZ > 128) ? 0 : 2; | |
514 | } | |
515 | else | |
516 | { | |
517 | if (absx > 5) | |
518 | wiiremote->nOrientation = (wiiremote->nLowX > 128) ? 3 : 1; | |
519 | } | |
520 | } | |
521 | else | |
522 | if (wiiremote->expType == WiiClassicController) | |
523 | { | |
524 | wiiremote->cButtonData = (unsigned short)(decrypt(dp[startByte + 4]) << 8) + decrypt(dp[startByte + 5]); | |
525 | wiiremote->cButtonData = ~wiiremote->cButtonData; // bit reverse | |
526 | ||
527 | wiiremote->cStickX1 = decrypt(dp[startByte]) & 0x3F; | |
528 | wiiremote->cStickY1 = decrypt(dp[startByte + 1]) & 0x3F; | |
529 | ||
530 | wiiremote->cStickX2 = (((decrypt(dp[startByte +0]) & 0xC0) >> 3) | | |
531 | ((decrypt(dp[startByte +1]) & 0xC0) >> 5) | | |
532 | ((decrypt(dp[startByte +2]) & 0x80) >> 7)) & 0x1F; | |
533 | wiiremote->cStickY2 = decrypt(dp[startByte + 2]) & 0x1F; | |
534 | ||
535 | wiiremote->cAnalogL = (((decrypt(dp[startByte +2]) & 0x60) >> 2) | | |
536 | ((decrypt(dp[startByte +3]) & 0xE0) >> 5)) & 0x1F; | |
537 | wiiremote->cAnalogR = decrypt(dp[startByte + 3]) & 0x1F; | |
538 | } | |
539 | } | |
540 | ||
541 | void handleIRData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) | |
542 | { | |
543 | int i; | |
544 | ||
545 | if (dp[1] == 0x33) | |
546 | { // 12 IR bytes | |
547 | int startByte = 0; | |
548 | for(i=0 ; i < 4 ; i++) | |
549 | { | |
550 | startByte = 7 + 3 * i; | |
551 | wiiremote->irData[i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; | |
552 | wiiremote->irData[i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; | |
553 | wiiremote->irData[i].s = dp[startByte +2] & 0x0F; | |
554 | } | |
555 | } | |
556 | else | |
557 | { // 10 IR bytes | |
558 | int shift = (dp[1] == 0x36) ? 4 : 7; | |
559 | int startByte = 0; | |
560 | for (i=0; i < 2; i++) { | |
561 | startByte = shift + 5 * i; | |
562 | wiiremote->irData[2*i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; | |
563 | wiiremote->irData[2*i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; | |
564 | wiiremote->irData[2*i].s = ((wiiremote->irData[2*i].x == wiiremote->irData[2*i].y) && (wiiremote->irData[2*i].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. | |
565 | ||
566 | wiiremote->irData[(2*i)+1].x = (dp[startByte +3] | ((dp[startByte +2] & 0x03) << 8)) & 0x3FF; | |
567 | wiiremote->irData[(2*i)+1].y = (dp[startByte +4] | ((dp[startByte +2] & 0x0C) << 6)) & 0x3FF; | |
568 | wiiremote->irData[(2*i)+1].s = ((wiiremote->irData[(2*i)+1].x == wiiremote->irData[(2*i)+1].y) && (wiiremote->irData[(2*i)+1].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. | |
569 | } | |
570 | } | |
571 | ||
572 | int p1 = -1; | |
573 | int p2 = -1; | |
574 | // we should modify this loop to take the points with the lowest s (the brightest ones) | |
575 | for (i=0 ; i<4 ; i++) { | |
576 | if (p1 == -1) { | |
577 | if (wiiremote->irData [i].s < 0x0F) | |
578 | p1 = i; | |
579 | } else { | |
580 | if (wiiremote->irData [i].s < 0x0F) { | |
581 | p2 = i; | |
582 | break; | |
583 | } | |
584 | } | |
585 | } | |
586 | ||
587 | double ox, oy; | |
588 | if ((p1 > -1) && (p2 > -1)) | |
589 | { | |
590 | int l = wiiremote->leftPoint; | |
591 | if (wiiremote->leftPoint == -1) | |
592 | { | |
593 | switch (wiiremote->orientation) | |
594 | { | |
595 | case 0: l = (wiiremote->irData[p1].x < wiiremote->irData[p2].x) ? 0 : 1; break; | |
596 | case 1: l = (wiiremote->irData[p1].y > wiiremote->irData[p2].y) ? 0 : 1; break; | |
597 | case 2: l = (wiiremote->irData[p1].x > wiiremote->irData[p2].x) ? 0 : 1; break; | |
598 | case 3: l = (wiiremote->irData[p1].y < wiiremote->irData[p2].y) ? 0 : 1; break; | |
599 | } | |
600 | ||
601 | wiiremote->leftPoint = l; | |
602 | } | |
603 | ||
604 | int r = 1-l; | |
605 | ||
606 | double dx = wiiremote->irData[r].x - wiiremote->irData[l].x; | |
607 | double dy = wiiremote->irData[r].y - wiiremote->irData[l].y; | |
608 | double d = hypot (dx, dy); | |
609 | ||
610 | dx /= d; | |
611 | dy /= d; | |
612 | ||
613 | double cx = (wiiremote->irData[l].x + wiiremote->irData[r].x)/kWiiIRPixelsWidth - 1; | |
614 | double cy = (wiiremote->irData[l].y + wiiremote->irData[r].y)/kWiiIRPixelsHeight - 1; | |
615 | ||
616 | ox = -dy*cy-dx*cx; | |
617 | oy = -dx*cy+dy*cx; | |
618 | ||
619 | // cam: | |
620 | // Compensate for distance. There must be fewer than 0.75*768 pixels between the spots for this to work. | |
621 | // In other words, you have to be far enough away from the sensor bar for the two spots to have enough | |
622 | // space on the image sensor to travel without one of the points going off the image. | |
623 | // note: it is working very well ... | |
624 | double gain = 4; | |
625 | if (d < (0.75 * kWiiIRPixelsHeight)) | |
626 | gain = 1 / (1 - d/kWiiIRPixelsHeight); | |
627 | ||
628 | ox *= gain; | |
629 | oy *= gain; | |
630 | ||
631 | wiiremote->angle = atan2(dy, dx); | |
632 | wiiremote->tracking = true; | |
633 | } | |
634 | else | |
635 | { | |
636 | ox = oy = -100; | |
637 | wiiremote->leftPoint = -1; // not tracking | |
638 | wiiremote->angle = -100; | |
639 | wiiremote->tracking = false; | |
640 | } | |
641 | ||
642 | wiiremote->posX = ox; | |
643 | wiiremote->posY = oy; | |
644 | } | |
645 | ||
646 | void handleButtonReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) | |
647 | { | |
648 | // wiimote buttons | |
649 | wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; | |
650 | ||
651 | // report contains extension data | |
652 | switch (dp[1]) | |
653 | { | |
654 | case 0x34 : | |
655 | case 0x35 : | |
656 | case 0x36 : | |
657 | case 0x37 : | |
658 | handleExtensionData(wiiremote, dp, dataLength); | |
659 | break; | |
660 | } | |
661 | ||
662 | // report contains IR data | |
663 | if (dp[1] & 0x02) | |
664 | { | |
665 | handleIRData(wiiremote, dp, dataLength); | |
666 | } | |
667 | ||
668 | // report contains motion sensor data | |
669 | if (dp[1] & 0x01) | |
670 | { | |
671 | wiiremote->accX = dp[4]; | |
672 | wiiremote->accY = dp[5]; | |
673 | wiiremote->accZ = dp[6]; | |
674 | ||
675 | wiiremote->lowZ = wiiremote->lowZ * 0.9 + wiiremote->accZ * 0.1; | |
676 | wiiremote->lowX = wiiremote->lowX * 0.9 + wiiremote->accX * 0.1; | |
677 | ||
678 | float absx = abs(wiiremote->lowX-128); | |
679 | float absz = abs(wiiremote->lowZ-128); | |
680 | ||
681 | if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; | |
682 | if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; | |
683 | ||
684 | if (absz >= absx) | |
685 | { | |
686 | if (absz > 5) | |
687 | wiiremote->orientation = (wiiremote->lowZ > 128)?0:2; | |
688 | } | |
689 | else | |
690 | { | |
691 | if (absx > 5) | |
692 | wiiremote->orientation = (wiiremote->lowX > 128)?3:1; | |
693 | } | |
694 | } | |
695 | } | |
696 | ||
697 | //-------------------------------------------------------------------------------------------- | |
698 | ||
699 | void myDataListener(IOBluetoothL2CAPChannelRef channel, void *dataPointer, UInt16 dataLength, void *refCon) | |
700 | { | |
701 | WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; | |
702 | unsigned char* dp = (unsigned char*)dataPointer; | |
703 | ||
704 | if (!wiiremote->device) | |
705 | return; | |
706 | ||
707 | //controller status (expansion port and battery level data) - received when report 0x15 sent to Wiimote (getCurrentStatus:) or status of expansion port changes. | |
708 | if (dp[1] == 0x20 && dataLength >= 8) | |
709 | { | |
710 | handleStatusReport(wiiremote, dp, dataLength); | |
711 | requestUpdates(wiiremote); // Make sure we keep getting state change reports. | |
712 | return; | |
713 | } | |
714 | ||
715 | if (dp[1] == 0x21) | |
716 | { | |
717 | handleRAMData(wiiremote, dp, dataLength); | |
718 | return; | |
719 | } | |
720 | ||
721 | if (dp[1] == 0x22) | |
722 | { // Write data response | |
723 | //NSLog(@"Write data response: %00x %00x %00x %00x", dp[2], dp[3], dp[4], dp[5]); | |
724 | return; | |
725 | } | |
726 | ||
727 | // report contains button info | |
728 | if ((dp[1] & 0xF0) == 0x30) | |
729 | { | |
730 | handleButtonReport(wiiremote, dp, dataLength); | |
731 | } | |
732 | } | |
733 | ||
734 | void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) | |
735 | { | |
736 | if (event->eventType == kIOBluetoothL2CAPChannelEventTypeData) | |
737 | { | |
738 | // In thise case: | |
739 | // event->u.newData.dataPtr is a pointer to the block of data received. | |
740 | // event->u.newData.dataSize is the size of the block of data. | |
741 | myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon); | |
742 | } | |
743 | else | |
744 | if (event->eventType == kIOBluetoothL2CAPChannelEventTypeClosed) | |
745 | { | |
746 | // In this case: | |
747 | // event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel | |
748 | // object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below). | |
749 | } | |
750 | } | |
751 | ||
752 | void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) | |
753 | { | |
754 | CFStringRef itsAddress, myAddress; | |
755 | ||
756 | itsAddress = IOBluetoothDeviceGetAddressString(objectRef); | |
757 | if (itsAddress != nil) | |
758 | { | |
759 | myAddress = IOBluetoothDeviceGetAddressString(((WiiRemoteRef)refCon)->device); | |
760 | if (myAddress != nil) | |
761 | { | |
762 | if (CFStringCompare(itsAddress, myAddress, 0) == kCFCompareEqualTo) | |
763 | { | |
764 | wiiremote_disconnect((WiiRemoteRef)refCon); | |
765 | } | |
766 | CFRelease(myAddress); | |
767 | } | |
768 | CFRelease(itsAddress); | |
769 | } | |
770 | } | |
771 | ||
772 | //-------------------------------------------------------------------------------------------- | |
773 | ||
774 | void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address) | |
775 | { | |
776 | CFStringRef cfstring; | |
777 | ||
778 | cfstring = IOBluetoothDeviceGetAddressString(wiiremote->device); | |
779 | CFStringGetCString(cfstring, address, 32, kCFStringEncodingMacRoman); | |
780 | CFRelease(cfstring); | |
781 | ||
782 | } | |
783 | ||
784 | //-------------------------------------------------------------------------------------------- | |
785 | ||
786 | Boolean wiiremote_connect(WiiRemoteRef wiiremote) | |
787 | { | |
788 | IOReturn ret; | |
789 | Boolean result; | |
790 | short i; | |
791 | ||
792 | if (wiiremote->device == nil) | |
793 | return false; | |
794 | ||
795 | // connect the device | |
796 | for (i=0; i<kTrial; i++) | |
797 | { | |
798 | ret = IOBluetoothDeviceOpenConnection(wiiremote->device, nil, nil); | |
799 | if ( ret == kIOReturnSuccess) | |
800 | break; | |
801 | usleep(kWait); // wait 10ms | |
802 | } | |
803 | if (i==kTrial) | |
804 | return false; | |
805 | ||
806 | wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, (void *)wiiremote); | |
807 | ||
808 | // performs an SDP query | |
809 | for (i=0; i<kTrial; i++) | |
810 | { | |
811 | ret = IOBluetoothDevicePerformSDPQuery(wiiremote->device, nil, nil); | |
812 | if ( ret == kIOReturnSuccess) | |
813 | break; | |
814 | usleep(kWait); // wait 10ms | |
815 | } | |
816 | if (i==kTrial) | |
817 | return false; | |
818 | ||
819 | result = openCChan(wiiremote); | |
820 | result = openIChan(wiiremote); | |
821 | ||
822 | if (result) | |
823 | { | |
824 | result = wiiremote_led(wiiremote, wiiremote->isLED1Illuminated, wiiremote->isLED2Illuminated, wiiremote->isLED3Illuminated, wiiremote->isLED4Illuminated); | |
825 | } | |
826 | ||
827 | if (result == false) | |
828 | { | |
829 | wiiremote_disconnect(wiiremote); | |
830 | return result; | |
831 | } | |
832 | ||
833 | wiiremote_getstatus(wiiremote); | |
834 | requestUpdates(wiiremote); | |
835 | ||
836 | readData(wiiremote, 0x0020, 7); // Get Accelerometer callibration data | |
837 | ||
838 | return true; | |
839 | } | |
840 | ||
841 | ||
842 | Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) | |
843 | { | |
844 | short i; | |
845 | ||
846 | if (wiiremote->cchan) | |
847 | { | |
848 | if (IOBluetoothDeviceIsConnected(wiiremote->device)) | |
849 | { | |
850 | for (i=0; i<kTrial; i++) | |
851 | { | |
852 | if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan) == kIOReturnSuccess) | |
853 | break; | |
854 | usleep(kWait); // wait 10ms | |
855 | } | |
856 | } | |
857 | if (i==kTrial) return false; | |
858 | IOBluetoothObjectRelease(wiiremote->cchan); | |
859 | wiiremote->cchan = nil; | |
860 | } | |
861 | ||
862 | if (wiiremote->ichan) | |
863 | { | |
864 | if (IOBluetoothDeviceIsConnected(wiiremote->device)) | |
865 | { | |
866 | for (i=0; i<kTrial; i++) | |
867 | { | |
868 | if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->ichan) == kIOReturnSuccess) | |
869 | break; | |
870 | } | |
871 | } | |
872 | if (i==kTrial) return false; | |
873 | IOBluetoothObjectRelease(wiiremote->ichan); | |
874 | wiiremote->ichan = nil; | |
875 | } | |
876 | ||
877 | if (wiiremote->device) | |
878 | { | |
879 | if (IOBluetoothDeviceIsConnected(wiiremote->device)) | |
880 | { | |
881 | for (i=0; i<kTrial; i++) | |
882 | { | |
883 | if (IOBluetoothDeviceCloseConnection(wiiremote->device) == kIOReturnSuccess) | |
884 | break; | |
885 | } | |
886 | } | |
887 | if (i==kTrial) return false; | |
888 | IOBluetoothObjectRelease(wiiremote->device); | |
889 | wiiremote->device = nil; | |
890 | } | |
891 | ||
892 | if (wiiremote->disconnectNotification != nil) | |
893 | { | |
894 | IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); | |
895 | wiiremote->disconnectNotification = nil; | |
896 | } | |
897 | ||
898 | return true; | |
899 | } | |
900 | ||
901 | //-------------------------------------------------------------------------------------------- | |
902 | //-------------------------------------------------------------------------------------------- | |
903 | ||
904 | Boolean requestUpdates(WiiRemoteRef wiiremote) | |
905 | { | |
906 | Boolean result; | |
907 | ||
908 | // Set the report type the Wiimote should send. | |
909 | unsigned char cmd[] = {0x12, 0x02, 0x30}; // Just buttons. | |
910 | ||
911 | if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; | |
912 | ||
913 | /* | |
914 | There are numerous status report types that can be requested. | |
915 | The IR reports must be matched with the data format set when initializing the IR camera: | |
916 | 0x36, 0x37 - 10 IR bytes go with Basic mode | |
917 | 0x33 - 12 IR bytes go with Extended mode | |
918 | 0x3e/0x3f - 36 IR bytes go with Full mode | |
919 | ||
920 | The Nunchuk and Classic controller use 6 bytes to report their state, so the reports that | |
921 | give more extension bytes don't provide any more info. | |
922 | ||
923 | Buttons | Accelerometer | IR | Extension | |
924 | --------------------+-------------------+-----------+------------- | |
925 | 0x30: Core Buttons | | | | |
926 | 0x31: Core Buttons | Accelerometer | | | |
927 | 0x32: Core Buttons | | | 8 bytes | |
928 | 0x33: Core Buttons | Accelerometer | 12 bytes | | |
929 | 0x34: Core Buttons | | | 19 bytes | |
930 | 0x35: Core Buttons | Accelerometer | | 16 bytes | |
931 | 0x36: Core Buttons | | 10 bytes | 9 bytes | |
932 | 0x37: Core Buttons | Accelerometer | 10 bytes | 6 bytes | |
933 | ?? 0x38: Core Buttons and Accelerometer with 16 IR bytes ?? | |
934 | 0x3d: | | | 21 bytes | |
935 | ||
936 | 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 16/36 IR bytes | |
937 | ||
938 | */ | |
939 | ||
940 | if (wiiremote->isIRSensorEnabled) | |
941 | { | |
942 | if (wiiremote->isExpansionPortEnabled) | |
943 | { | |
944 | cmd[2] = 0x36; // Buttons, 10 IR Bytes, 9 Extension Bytes | |
945 | wiiremote->wiiIRMode = kWiiIRModeBasic; | |
946 | } | |
947 | else | |
948 | { | |
949 | cmd[2] = 0x33; // Buttons, Accelerometer, and 12 IR Bytes. | |
950 | wiiremote->wiiIRMode = kWiiIRModeExtended; | |
951 | } | |
952 | ||
953 | // Set IR Mode | |
954 | writeData(wiiremote, (darr){ wiiremote->wiiIRMode }, 0x04B00033, 1); | |
955 | usleep(kWait); // wait 10ms | |
956 | } | |
957 | else | |
958 | { | |
959 | if (wiiremote->isExpansionPortEnabled) | |
960 | { | |
961 | cmd[2] = 0x34; // Buttons, 19 Extension Bytes | |
962 | } | |
963 | else | |
964 | { | |
965 | cmd[2] = 0x30; // Buttons | |
966 | } | |
967 | } | |
968 | ||
969 | if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; // Add Accelerometer | |
970 | ||
971 | usleep(kWait); // wait 10ms | |
972 | result = sendCommand(wiiremote, cmd, 3); | |
973 | ||
974 | return(result); | |
975 | } | |
976 | ||
977 | //-------------------------------------------------------------------------------------------- | |
978 | ||
979 | Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled) | |
980 | { | |
981 | wiiremote->isMotionSensorEnabled = enabled; | |
982 | return requestUpdates(wiiremote); | |
983 | } | |
984 | ||
985 | Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled) | |
986 | { | |
987 | ||
988 | wiiremote->isVibrationEnabled = enabled; | |
989 | return requestUpdates(wiiremote); | |
990 | } | |
991 | ||
992 | Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) | |
993 | { | |
994 | unsigned char cmd[] = {0x11, 0x00}; | |
995 | if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; | |
996 | if (enabled1) cmd[1] |= 0x10; | |
997 | if (enabled2) cmd[1] |= 0x20; | |
998 | if (enabled3) cmd[1] |= 0x40; | |
999 | if (enabled4) cmd[1] |= 0x80; | |
1000 | ||
1001 | wiiremote->isLED1Illuminated = enabled1; | |
1002 | wiiremote->isLED2Illuminated = enabled2; | |
1003 | wiiremote->isLED3Illuminated = enabled3; | |
1004 | wiiremote->isLED4Illuminated = enabled4; | |
1005 | ||
1006 | return sendCommand(wiiremote, cmd, 2); | |
1007 | } | |
1008 | ||
1009 | Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled) | |
1010 | { | |
1011 | wiiremote->isExpansionPortEnabled = enabled; | |
1012 | if (wiiremote->isExpansionPortAttached == false) | |
1013 | { | |
1014 | wiiremote->isExpansionPortEnabled = false; | |
1015 | } | |
1016 | else | |
1017 | { | |
1018 | readData(wiiremote, 0x04A40020, 16); //get calbdata | |
1019 | } | |
1020 | ||
1021 | return requestUpdates(wiiremote); | |
1022 | } | |
1023 | ||
1024 | Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) | |
1025 | { | |
1026 | Boolean ret; | |
1027 | ||
1028 | wiiremote->isIRSensorEnabled = enabled; | |
1029 | ||
1030 | // ir enable 1 | |
1031 | unsigned char cmd[] = {0x13, 0x00}; | |
1032 | if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; | |
1033 | if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; | |
1034 | if ((ret = sendCommand(wiiremote, cmd, 2)) == false) | |
1035 | return ret; | |
1036 | usleep(kWait); | |
1037 | ||
1038 | // set register 0x1a (ir enable 2) | |
1039 | unsigned char cmd2[] = {0x1a, 0x00}; | |
1040 | if (enabled) cmd2[1] |= 0x04; | |
1041 | if ((ret = sendCommand(wiiremote, cmd2, 2)) == false) | |
1042 | return ret; | |
1043 | usleep(kWait); | |
1044 | ||
1045 | if(enabled) | |
1046 | { | |
1047 | // based on marcan's method, found on wiili wiki: | |
1048 | // tweaked to include some aspects of cliff's setup procedure in the hopes | |
1049 | // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) | |
1050 | // the sleeps help it it seems | |
1051 | usleep(kWait); | |
1052 | if ((ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1)) == false) return ret; | |
1053 | usleep(kWait); | |
1054 | if ((ret = writeData(wiiremote, (darr){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xC0}, 0x04B00000, 9)) == false) return ret; | |
1055 | usleep(kWait); | |
1056 | if ((ret = writeData(wiiremote, (darr){0x40, 0x00}, 0x04B0001A, 2)) == false) return ret; | |
1057 | usleep(kWait); | |
1058 | if ((ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1)) == false) return ret; | |
1059 | usleep(kWait); | |
1060 | ||
1061 | requestUpdates(wiiremote); | |
1062 | } | |
1063 | else | |
1064 | { | |
1065 | // probably should do some writes to power down the camera, save battery | |
1066 | // but don't know how yet. | |
1067 | ||
1068 | ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); | |
1069 | ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); | |
1070 | ret = wiiremote_expansion(wiiremote, wiiremote->isExpansionPortEnabled); | |
1071 | } | |
1072 | ||
1073 | return ret; | |
1074 | } | |
1075 | ||
1076 | Boolean wiiremote_getstatus(WiiRemoteRef wiiremote) | |
1077 | { | |
1078 | unsigned char cmd[] = {0x15, 0x00}; | |
1079 | return sendCommand(wiiremote, cmd, 2); | |
1080 | } | |
1081 | ||
1082 |
0 | // wiiremote.h | |
1 | // Copyright by Masayuki Akamatsu | |
2 | // Based on "DarwiinRemote" by Hiroaki Kimura | |
3 | ||
4 | #define BLUETOOTH_VERSION_USE_CURRENT | |
5 | //#include <AvailabilityMacros.h> | |
6 | #include <math.h> | |
7 | #include <CoreFoundation/CoreFoundation.h> | |
8 | //#include <CoreFoundation/CFMachPort.h> | |
9 | #include <IOBluetooth/IOBluetoothUserLib.h> | |
10 | ||
11 | typedef unsigned char WiiIRModeType; | |
12 | enum { | |
13 | kWiiIRModeBasic = 0x01, | |
14 | kWiiIRModeExtended = 0x03, | |
15 | kWiiIRModeFull = 0x05 | |
16 | }; | |
17 | ||
18 | typedef struct { | |
19 | int x, y, s; | |
20 | } IRData; | |
21 | ||
22 | typedef struct { | |
23 | unsigned char accX_zero, accY_zero, accZ_zero, accX_1g, accY_1g, accZ_1g; | |
24 | } WiiAccCalibData; | |
25 | ||
26 | typedef struct { | |
27 | unsigned char x_min, x_max, x_center, y_min, y_max, y_center; | |
28 | } WiiJoyStickCalibData; | |
29 | ||
30 | typedef UInt16 WiiButtonType; | |
31 | enum { | |
32 | WiiRemoteAButton, | |
33 | WiiRemoteBButton, | |
34 | WiiRemoteOneButton, | |
35 | WiiRemoteTwoButton, | |
36 | WiiRemoteMinusButton, | |
37 | WiiRemoteHomeButton, | |
38 | WiiRemotePlusButton, | |
39 | WiiRemoteUpButton, | |
40 | WiiRemoteDownButton, | |
41 | WiiRemoteLeftButton, | |
42 | WiiRemoteRightButton, | |
43 | ||
44 | WiiNunchukZButton, | |
45 | WiiNunchukCButton, | |
46 | ||
47 | WiiClassicControllerXButton, | |
48 | WiiClassicControllerYButton, | |
49 | WiiClassicControllerAButton, | |
50 | WiiClassicControllerBButton, | |
51 | WiiClassicControllerLButton, | |
52 | WiiClassicControllerRButton, | |
53 | WiiClassicControllerZLButton, | |
54 | WiiClassicControllerZRButton, | |
55 | WiiClassicControllerUpButton, | |
56 | WiiClassicControllerDownButton, | |
57 | WiiClassicControllerLeftButton, | |
58 | WiiClassicControllerRightButton, | |
59 | WiiClassicControllerMinusButton, | |
60 | WiiClassicControllerHomeButton, | |
61 | WiiClassicControllerPlusButton | |
62 | }; | |
63 | ||
64 | ||
65 | typedef UInt16 WiiExpansionPortType; | |
66 | enum{ | |
67 | WiiExpNotAttached, | |
68 | WiiNunchuk, | |
69 | WiiClassicController | |
70 | }; | |
71 | ||
72 | typedef UInt16 WiiAccelerationSensorType; | |
73 | enum{ | |
74 | WiiRemoteAccelerationSensor, | |
75 | WiiNunchukAccelerationSensor | |
76 | }; | |
77 | ||
78 | ||
79 | typedef UInt16 WiiJoyStickType; | |
80 | enum{ | |
81 | WiiNunchukJoyStick, | |
82 | WiiClassicControllerLeftJoyStick, | |
83 | WiiClassicControllerRightJoyStick | |
84 | }; | |
85 | ||
86 | ||
87 | typedef struct _WiiRemoteRec | |
88 | { | |
89 | IOBluetoothDeviceInquiryRef inquiry; | |
90 | IOBluetoothDeviceRef device; | |
91 | IOBluetoothL2CAPChannelRef ichan; | |
92 | IOBluetoothL2CAPChannelRef cchan; | |
93 | ||
94 | CFStringRef address; | |
95 | ||
96 | unsigned char accX; | |
97 | unsigned char accY; | |
98 | unsigned char accZ; | |
99 | unsigned short buttonData; | |
100 | ||
101 | float lowZ; | |
102 | float lowX; | |
103 | int orientation; | |
104 | int leftPoint; // is point 0 or 1 on the left. -1 when not tracking. | |
105 | ||
106 | float posX; | |
107 | float posY; | |
108 | float angle; | |
109 | Boolean tracking; | |
110 | ||
111 | WiiExpansionPortType expType; | |
112 | WiiAccCalibData wiiCalibData, nunchukCalibData; | |
113 | WiiJoyStickCalibData nunchukJoyStickCalibData; | |
114 | WiiIRModeType wiiIRMode; | |
115 | IRData irData[4]; | |
116 | double batteryLevel; | |
117 | ||
118 | Boolean readingRegister; | |
119 | Boolean isMotionSensorEnabled; | |
120 | Boolean isIRSensorEnabled; | |
121 | Boolean isVibrationEnabled; | |
122 | Boolean isExpansionPortEnabled; | |
123 | Boolean initExpPort; | |
124 | Boolean isLED1Illuminated; | |
125 | Boolean isLED2Illuminated; | |
126 | Boolean isLED3Illuminated; | |
127 | Boolean isLED4Illuminated; | |
128 | ||
129 | Boolean isExpansionPortAttached; | |
130 | ||
131 | IOBluetoothUserNotificationRef disconnectNotification; | |
132 | ||
133 | //nunchuk | |
134 | unsigned char nStickX; | |
135 | unsigned char nStickY; | |
136 | unsigned char nAccX; | |
137 | unsigned char nAccY; | |
138 | unsigned char nAccZ; | |
139 | unsigned char nButtonData; | |
140 | ||
141 | float nLowZ; | |
142 | float nLowX; | |
143 | int nOrientation; | |
144 | ||
145 | //classic controller | |
146 | unsigned short cButtonData; | |
147 | unsigned char cStickX1; | |
148 | unsigned char cStickY1; | |
149 | unsigned char cStickX2; | |
150 | unsigned char cStickY2; | |
151 | unsigned char cAnalogL; | |
152 | unsigned char cAnalogR; | |
153 | ||
154 | } WiiRemoteRec, *WiiRemoteRef; | |
155 | ||
156 | void wiiremote_init(WiiRemoteRef wiiremote); | |
157 | Boolean wiiremote_isconnected(WiiRemoteRef wiiremote); | |
158 | Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address); | |
159 | Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote); | |
160 | Boolean wiiremote_connect(WiiRemoteRef wiiremote); | |
161 | Boolean wiiremote_disconnect(WiiRemoteRef wiiremote); | |
162 | void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address); | |
163 | Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled); | |
164 | Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled); | |
165 | Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled); | |
166 | Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); | |
167 | Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled); | |
168 | Boolean wiiremote_getstatus(WiiRemoteRef wiiremote); | |
169 |
2044 | 2044 | if (!validItem) break; |
2045 | 2045 | if (skipItem) continue; |
2046 | 2046 | |
2047 | if (sc_DirectoryExists(diritem)) { | |
2048 | success = passOne_ProcessDir(diritem, level + 1); | |
2049 | } else { | |
2050 | success = passOne_ProcessOneFile(diritem, level + 1); | |
2051 | } | |
2047 | if (sc_DirectoryExists(diritem)) { | |
2048 | success = passOne_ProcessDir(diritem, level + 1); | |
2049 | } else { | |
2050 | success = passOne_ProcessOneFile(diritem, level + 1); | |
2051 | } | |
2052 | 2052 | |
2053 | 2053 | if (!success) break; |
2054 | 2054 | } |
2124 | 2124 | } |
2125 | 2125 | |
2126 | 2126 | // sekhar's replacement |
2127 | bool passOne_ProcessOneFile(char *filenamearg, int level) | |
2127 | bool passOne_ProcessOneFile(const char * filenamearg, int level) | |
2128 | 2128 | { |
2129 | 2129 | bool success = true; |
2130 | 2130 | |
2131 | 2131 | bool isAlias = false; |
2132 | 2132 | // on non-Darwin, sc_ResolveIfAlias always returns original path |
2133 | 2133 | char filename[MAXPATHLEN]; |
2134 | sc_ResolveIfAlias(filenamearg, filename, isAlias, MAXPATHLEN); | |
2134 | int status = sc_ResolveIfAlias(filenamearg, filename, isAlias, MAXPATHLEN); | |
2135 | ||
2136 | if (status<0) { | |
2137 | printf("WARNING: skipping invalid symbolic link: %s\n", filenamearg); | |
2138 | return success; | |
2139 | } | |
2135 | 2140 | |
2136 | 2141 | #ifdef ENABLE_LIBRARY_CONFIGURATOR |
2137 | 2142 | if (gLibraryConfig && gLibraryConfig->pathIsExcluded(filename)) { |
2140 | 2145 | } |
2141 | 2146 | #endif |
2142 | 2147 | |
2143 | PyrSymbol *fileSym; | |
2144 | 2148 | if (isValidSourceFileName(filename)) { |
2145 | 2149 | gNumCompiledFiles++; |
2146 | fileSym = getsym(filename); | |
2150 | PyrSymbol * fileSym = getsym(filename); | |
2147 | 2151 | fileSym->u.source = NULL; |
2148 | 2152 | if (startLexer(fileSym, -1, -1, -1)) { |
2149 | 2153 | while (parseOneClass(fileSym)) { }; |
2153 | 2157 | success = false; |
2154 | 2158 | } |
2155 | 2159 | } else { |
2156 | #ifndef SC_WIN32 | |
2157 | // check if this is a symlink | |
2158 | char realpathname[MAXPATHLEN]; | |
2159 | realpath(filename, realpathname); | |
2160 | if (strncmp(filename, realpathname, strlen(filename))) { | |
2161 | if (sc_DirectoryExists(realpathname)) | |
2162 | success = passOne_ProcessDir(realpathname, level); | |
2163 | } | |
2164 | #else | |
2165 | // under window, we're sure it's a file so wer don't do anything... | |
2166 | // maybe processing .lnk files could be interesting... | |
2167 | // $$$todo fixme add .lnk file parsing... | |
2168 | // (see http://www.thecodeproject.com/managedcpp/mcppshortcuts.asp) | |
2169 | #endif | |
2170 | } | |
2160 | if (sc_DirectoryExists(filename)) | |
2161 | success = passOne_ProcessDir(filename, level); | |
2162 | } | |
2171 | 2163 | return success; |
2172 | 2164 | } |
2173 | 2165 |
1272 | 1272 | sizeof(PyrSlot) * classClassNumInstVars); |
1273 | 1273 | memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols, |
1274 | 1274 | slotRawSymbolArray(&metaSuperClass->instVarNames)->symbols, |
1275 | sizeof(PyrSlot) * classClassNumInstVars); | |
1275 | sizeof(PyrSymbol*) * classClassNumInstVars); | |
1276 | 1276 | slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars; |
1277 | 1277 | slotRawObject(&metaclassobj->instVarNames)->size = classClassNumInstVars; |
1278 | 1278 | //dumpObject((PyrObject*)metaclassobj); |
1289 | 1289 | sizeof(PyrSlot) * superInstVars); |
1290 | 1290 | memcpy(slotRawSymbolArray(&classobj->instVarNames)->symbols, |
1291 | 1291 | slotRawSymbolArray(&superClass->instVarNames)->symbols, |
1292 | sizeof(PyrSlot) * superInstVars); | |
1292 | sizeof(PyrSymbol*) * superInstVars); | |
1293 | 1293 | slotRawObject(&classobj->iprototype)->size = superInstVars; |
1294 | 1294 | slotRawObject(&classobj->instVarNames)->size = superInstVars; |
1295 | 1295 | } |
1486 | 1486 | |
1487 | 1487 | addIntrinsicVar(class_thread, "environment", &o_nil); |
1488 | 1488 | addIntrinsicVar(class_thread, "exceptionHandler", &o_nil); |
1489 | ||
1489 | ||
1490 | 1490 | addIntrinsicVar(class_thread, "executingPath", &o_nil); |
1491 | 1491 | addIntrinsicVar(class_thread, "oldExecutingPath", &o_nil); |
1492 | 1492 |
2011 | 2011 | { |
2012 | 2012 | float xa = ZIN0(0); |
2013 | 2013 | |
2014 | nova::over_vec_simd(OUT(0), IN(1), xa, inNumSamples); | |
2014 | nova::over_vec_simd(OUT(0), xa, IN(1), inNumSamples); | |
2015 | 2015 | unit->mPrevA = xa; |
2016 | 2016 | } |
2017 | 2017 |
166 | 166 | { |
167 | 167 | if (full_rate) |
168 | 168 | return GRAIN_IN_AT(unit, index, offset); |
169 | ||
170 | if (INRATE(index) == calc_DemandRate) | |
171 | return DEMANDINPUT_A(index, offset + 1); | |
169 | 172 | else |
170 | 173 | return IN0(index); |
171 | 174 | } |
1176 | 1179 | |
1177 | 1180 | // end add // |
1178 | 1181 | |
1179 | int nsmps = sc_min(grain->counter, inNumSamples); | |
1182 | int nsmps = sc_min(grain->counter, inNumSamples - position); | |
1180 | 1183 | |
1181 | 1184 | if (grain->winType < 0.) |
1182 | 1185 | GRAIN_BUF_PLAY_GRAIN(INTERNAL); |
57 | 57 | |
58 | 58 | struct LagControl : public IOUnit |
59 | 59 | { |
60 | float m_b1[kMaxLags]; | |
61 | float m_y1[kMaxLags]; | |
60 | float * m_b1; | |
61 | float * m_y1; | |
62 | 62 | }; |
63 | 63 | |
64 | 64 | |
351 | 351 | |
352 | 352 | void LagControl_Ctor(LagControl* unit) |
353 | 353 | { |
354 | int numChannels = unit->mNumInputs; | |
355 | float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; | |
356 | ||
357 | char * chunk = (char*)RTAlloc(unit->mWorld, numChannels * 2 * sizeof(float)); | |
358 | unit->m_y1 = (float*)chunk; | |
359 | unit->m_b1 = unit->m_y1 + numChannels; | |
360 | ||
361 | for (int i=0; i<numChannels; ++i, mapin++) { | |
362 | unit->m_y1[i] = **mapin; | |
363 | float lag = ZIN0(i); | |
364 | unit->m_b1[i] = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); | |
365 | } | |
366 | ||
354 | 367 | if (unit->mNumOutputs == 1) { |
355 | 368 | SETCALC(LagControl_next_1); |
356 | 369 | LagControl_next_1(unit, 1); |
358 | 371 | SETCALC(LagControl_next_k); |
359 | 372 | LagControl_next_k(unit, 1); |
360 | 373 | } |
361 | int numChannels = unit->mNumInputs; | |
362 | float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; | |
363 | for (int i=0; i<numChannels; ++i, mapin++) { | |
364 | unit->m_y1[i] = **mapin; | |
365 | float lag = ZIN0(i); | |
366 | unit->m_b1[i] = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); | |
367 | } | |
374 | } | |
375 | ||
376 | void LagControl_Dtor(LagControl* unit) | |
377 | { | |
378 | RTFree(unit->mWorld, unit->m_y1); | |
368 | 379 | } |
369 | 380 | |
370 | 381 | ////////////////////////////////////////////////////////////////////////////////////////////////// |
1931 | 1942 | DefineDtorUnit(OffsetOut); |
1932 | 1943 | DefineDtorUnit(LocalIn); |
1933 | 1944 | DefineSimpleUnit(XOut); |
1934 | DefineSimpleUnit(LagControl); | |
1945 | DefineDtorUnit(LagControl); | |
1935 | 1946 | DefineDtorUnit(AudioControl); |
1936 | 1947 | DefineUnit("Control", sizeof(Unit), (UnitCtorFunc)&Control_Ctor, 0, 0); |
1937 | 1948 | DefineUnit("TrigControl", sizeof(Unit), (UnitCtorFunc)&TrigControl_Ctor, 0, 0); |
637 | 637 | float z = phase; |
638 | 638 | ZXP(out) = 1.f - z*z; |
639 | 639 | } |
640 | phase += ZXP(freq) * freqmul; | |
640 | // Note: the following two lines were originally one, but seems to compile wrong on mac | |
641 | float phaseadd = ZXP(freq) * freqmul; | |
642 | phase += phaseadd; | |
641 | 643 | ); |
642 | 644 | |
643 | 645 | unit->mPhase = phase; |
702 | 704 | z = phase; |
703 | 705 | } |
704 | 706 | ZXP(out) = z * z * (6.f - 4.f * z) - 1.f; |
705 | phase += ZXP(freq) * freqmul; | |
707 | float phaseadd = ZXP(freq); | |
708 | phase += phaseadd * freqmul; | |
706 | 709 | ); |
707 | 710 | |
708 | 711 | unit->mPhase = phase; |
1075 | 1075 | unit->m_prevtrig = 0.f; |
1076 | 1076 | unit->mLevel = 0.f; |
1077 | 1077 | |
1078 | ZOUT0(0) = 0.f; | |
1078 | ZOUT0(0) = ZIN0(1) > 0.f ? ZIN0(0) : 0.f; | |
1079 | 1079 | } |
1080 | 1080 | |
1081 | 1081 |
165 | 165 | { \ |
166 | 166 | if (inNumSamples) { \ |
167 | 167 | float x = DEMANDINPUT_A(0, inNumSamples); \ |
168 | OUT0(0) = sc_isnan(x) ? NAN : sc_cpsoct(x); \ | |
168 | OUT0(0) = sc_isnan(x) ? NAN : function(x); \ | |
169 | 169 | } else { \ |
170 | 170 | RESETINPUT(0); \ |
171 | 171 | } \ |
1 | 1 | dnl file: configure.in |
2 | 2 | dnl contents: autoconf template |
3 | 3 | dnl author: stefan kersten <steve@k-hornz.de> |
4 | dnl CVS: $Id: configure.in 2231 2003-11-28 11:06:57Z kersten $ | |
4 | dnl CVS: $Id$ | |
5 | 5 | dnl =================================================================== |
6 | 6 | |
7 | 7 | # initialize autoconf |
67 | 67 | void sc_SetDenormalFlags() |
68 | 68 | { |
69 | 69 | // all Macs have SSE |
70 | _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); | |
70 | 71 | _mm_setcsr(_mm_getcsr() | 0x40); |
71 | 72 | } |
72 | 73 |
252 | 252 | bool result; |
253 | 253 | inWorld->mDriverLock->Lock(); |
254 | 254 | SC_AudioDriver *driver = AudioDriver(inWorld); |
255 | if (!driver) return false; | |
255 | if (!driver) { | |
256 | inWorld->mDriverLock->Unlock(); | |
257 | return false; | |
258 | } | |
256 | 259 | inPacket->mIsBundle = gIsBundle.checkIsBundle((int32*)inPacket->mData); |
257 | 260 | FifoMsg fifoMsg; |
258 | 261 | fifoMsg.Set(inWorld, Perform_ToEngine_Msg, FreeOSCPacket, (void*)inPacket); |
1293 | 1293 | SCErr meth_clearSched(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); |
1294 | 1294 | SCErr meth_clearSched(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) |
1295 | 1295 | { |
1296 | inWorld->hw->mAudioDriver->ClearSched(); | |
1296 | if(inWorld->mRealTime){ | |
1297 | inWorld->hw->mAudioDriver->ClearSched(); | |
1298 | } | |
1297 | 1299 | return kSCErr_None; |
1298 | 1300 | } |
1299 | 1301 |
0 | 0 | Changes are listed below, grouped under each point release of SuperCollider. |
1 | ||
2 | SuperCollider v3.4.2, released 2011-03 | |
3 | ====================================== | |
4 | ||
5 | Bugfixes: | |
6 | --------- | |
7 | ||
8 | * 2010-06-05 fix Latch first sample output bug: if trigger > 0 initially, latch should not output 0 - jh | |
9 | * 2010-09-04 fix firstArg behavior in BinaryOpUGen by a list-approved hack - jh | |
10 | * 2010-10-01 fix SConstruct so that libscsynth and libsclang get SONAME entries - ds | |
11 | * 2010-11-13 grainBuf: audio-rate trigger fix - tb | |
12 | * 2010-11-15 generate libsclang and libscsynth with .so.1 extension (and soname) on linux - ds | |
13 | * 2010-11-15 scons create symlinks from libX.so to libX.so.1 on linux, and install them - ds | |
14 | * 2010-11-16 added .htm files to SConstruct as approved help file extension - mb | |
15 | * 2010-11-28 compile fix for curl support - tb | |
16 | * 2010-11-28 prevent asBus from breaking when called with no numChannels - jh | |
17 | * 2010-12-03 grain ugens: demand ugen input fix - tb | |
18 | * 2010-12-05 SystemClock and TempoClock sched and schedAbs with inf time doesn't schedule the task in the first place. backported from master - tb | |
19 | * 2010-12-08 prString_FindRegexp fix: match char array was too short to hold null termination - jl | |
20 | * 2010-12-11 fix classbrowser colors bugs. backported from master - tb | |
21 | * 2010-12-12 fixes the bug where installed quark help files would not be detected - tb/ar | |
22 | * 2010-12-13 mark inherited methods in class browser by background colour. backported from master - tb | |
23 | * 2010-12-30 Pipe does not remove closed pipes from openFiles - jh | |
24 | * 2010-12-30 fix String:rotate - pb | |
25 | * 2011-01-02 unit generators: LagControl - fix initialization order - jh | |
26 | * 2011-01-02 unit generators: LagControl - dynamically allocate buffer for filter states - tb | |
27 | * 2011-01-07 fixed iOS compilation and backported changes from master branch - ab | |
28 | * 2011-01-06 array primitives: fix allTuples and unlace - pb | |
29 | * 2011-01-07 sclang: makeIntrinsicClass - correct bounds for memcpy - tb | |
30 | * 2011-01-08 sclang: prString_FindRegexp - fill array after allocating objects - tb | |
31 | * 2011-01-14 sclang: prString_FindRegexp ensure correct size of results array during gc calls - tb | |
32 | * 2011-02-27 sclang: ensure minimum stack size - tb | |
33 | * 2011-03-09 SCVim: avoid generating scvim help cache if not currently in scvim - ds | |
34 | * 2011-03-11 fix the Event type 'note' (fixes rendering patterns to audio files) - rk | |
35 | ||
36 | ||
37 | ||
38 | SuperCollider v3.4.1, released 2010-11 | |
39 | ====================================== | |
40 | ||
41 | * 2010-07-12 remove accidental debug messages from SCView (on mac, posted a lot of info to Console, could affect performance) - ds | |
42 | * 2010-09-11 bug in audio rate mapping fixed, when new source object was inserted in a mapped node proxy - jr | |
43 | * 2010-07-11 Collections should behave as reasonably as possible when empty - some fixes to better this - jr | |
44 | * 2010-07-11 SynthDef:add now sends to all running servers if no libname is given. SynthDescs are still added to the global SynthDescLib. If you want to handle multiple SynthDesc libs, you have to add the servers to each of them explicitly - jr | |
45 | * 2010-07-12 PanAz: added support for audio-rate pos arg - lfsaw | |
46 | * 2010-07-18 improved the sclang syntax highlighting parses - Patrick Borgeat | |
47 | * 2010-07-30 Dreset UGen allows to reset the child UGens on its input - jr | |
48 | * 2010-08-05 storeOn / asCompileString now simplifies its output. Default arguments that are given in the *new method anyhow are omitted - jr | |
49 | * 2010-08-06 Dictionary merge and blend methods - jr | |
50 | * 2010-08-09 method overwrite messages not posted by default, rather a message inviting people to run Main:overwriteMsg for the info - ds | |
51 | * 2010-08-13 MethodOverride class to encapsule information on overridden messages, inviting people to run MethodOverride.printAll - jr | |
52 | * 2010-08-13 add size arg to Signal:zeroPad - jr and jh | |
53 | * 2010-08-18 Pevent now uses default event if no event is passed in - jr | |
54 | * 2010-08-18 added a shortcut to the rather tedious .asCompileString method. In analogy to object.postcs, object.cs returns the compile string - jr | |
55 | * 2010-08-20 audio driver for scsynth running on Android (through JNI) - ds | |
56 | * 2010-08-24 un-deprecate scsynth's ability to use internal "green" FFT lib, for embedded devices etc - ds | |
57 | * 2010-08-28 no 'record' button for remote server GUIs, since path not generally known - ds | |
58 | * 2010-09-02 token threading for sclang interpreter - tb | |
59 | * 2010-09-07 when looking for a code file (openCodeFile) or cmd-J, it is now enough to select a full line, instead of having to select both words around the colon - jr | |
60 | * 2010-09-07 added methods for better navigation in the class tree (findOverriddenMethod) - jr | |
61 | * 2010-09-10 add method: Complex:abs to fit common usage - jr | |
62 | * 2010-09-12 added Dwrand UGen - jr | |
63 | * 2010-09-15 SystemClock and TempoClock sched and schedAbs with inf time doesn't schedule the task in the first place - jr | |
64 | * 2010-10-07 change the mac HID error-handler code to output errors to sc post window rather than to mac log; removes a pascal-string issue - ds | |
65 | * 2010-10-19 Ndef now releses its bus when server was quit or just booted - jr | |
66 | * 2010-10-20 retain the path to the file in which an error has occurred and post it - jr | |
67 | ||
68 | ||
69 | Bugfixes: | |
70 | --------- | |
71 | * 2010-07-10 protecting the server against malformatted SynthDef names - jr | |
72 | * 2010-06-28 syntaxColorize fix for double-backslashes, thanks Patrick Borgeat for the patch - ds | |
73 | * 2010-07-24 catch crash in the case that one tries to define a unique method using a return value directly - jr | |
74 | * 2010-09-07 UGen:clip, :wrap, :fold now apply correctly to scalar-rate signals; also methodSelectorForRate tweak for which class is asked - ds | |
75 | * 2010-09-09 fix a bug for trigger signals in Demand.kr that hold longer than one control period - jr | |
76 | * 2010-09-12 fix bug: 2994009. LFPar and LFCub audio rate modulation frequency argument work now - jr | |
77 | * 2010-09-19 fix to JITGui, when numItems is not supplied - jr | |
78 | * 2010-10-10 remove more crufty NSLog debug messages - ds | |
79 | * 2010-10-13 fix SCUserView:receiveDrag to receive mouse co-ordinates; thanks Daniel van den Eijkel - ds | |
80 | * 2010-10-19 debian-style scvim-check-if-plugin-is-active, brought upstream - ds | |
81 | * 2010-10-19 bug in audio rate mapping fixed, when new source object was inserted in a mapped node proxy - jr | |
82 | * 2010-10-19 partial fix for bugs item #2994009 - seems to fix LFPar but not LFCub. More work needed - ds | |
83 | * 2010-10-19 DC: fix multichannel expansion - tb | |
84 | * 2010-10-19 fix to demand rate unary op ugens, thanks james harkins - tb | |
85 | * 2010-10-19 Ugens: LinLin/LinExp fixes - tb | |
86 | * 2010-10-19 only /clearSched if RT - to fix tracker item #3033454 - tb | |
87 | * 2010-10-19 UGens: binary operators - fix scalar/signal division - tb | |
88 | * 2010-10-19 fix bug 2988525: SynthDef:writeDefFile appends path correctly - tb | |
89 | * 2010-10-19 ProcessOSCPacket: fix possible deadlock - tb | |
90 | * 2010-10-19 fix network address handling - albert graef | |
91 | * 2010-11-05 fix memory issues in regular expressions: correct memory management in prString_FindRegexp - tb | |
92 | * 2010-11-07 sclang: correct symlink handling - tb, ar | |
1 | 93 | |
2 | 94 | SuperCollider v3.4, released 2010-07 |
3 | 95 | ==================================== |
29 | 121 | * 2010-02-18 scvim: now compatible with gnu screen, opens post window using screen, making it compatible with a pure-CLI environment - ds |
30 | 122 | * 2010-02-xx add the Deployment32-64 build style for building on OS X (10.5 and greater) - jp |
31 | 123 | * 2010-03-10 SynthDef:memStore deprecated in favour of the more coherent and typeable SynthDef:add - jr |
32 | * 2010-04-11 Moved some more experimental JITLib classes to ÒJITLib extensions" Quark - jr | |
124 | * 2010-04-11 Moved some more experimental JITLib classes to "JITLib extensions" Quark - jr | |
33 | 125 | |
34 | 126 | |
35 | 127 | Bugfixes: |
68 | 160 | * 2010-03-11 SequenceableCollection:reduce no longer returns nil if the collection has only 1 element - ds |
69 | 161 | * 2010-03-28 fix memory leak of empty command line, for interactive sclang mode - tb |
70 | 162 | * 2010-03-29 main menu for Mac lang editor app: correction to key for evaluate selection, used to be return, now return+shift - nc |
163 | * 2010-04-19 fix missing font issue in Plotter -jr | |
71 | 164 | |
72 | 165 | Other additions/improvements: |
73 | 166 | ----------------------------- |
14 | 14 | // } |
15 | 15 | operator_ { arg op; |
16 | 16 | operator = op; |
17 | specialIndex = operator.specialIndex; | |
18 | // 'firstArg' check is necessary for audio-rate Demand units | |
19 | if(specialIndex < 0 and: { operator != 'firstArg' }) { | |
17 | // 'firstArg' exists in the server | |
18 | // but the 'specialIndex' primitive doesn't report the right value | |
19 | // admittedly this is a hack, but the hack was approved on sc-dev | |
20 | if(operator == 'firstArg') { | |
21 | specialIndex = 46 | |
22 | } { | |
23 | specialIndex = operator.specialIndex; | |
24 | }; | |
25 | if(specialIndex < 0) { | |
20 | 26 | Error("Operator '%' applied to a UGen is not supported in scsynth".format(operator)).throw |
21 | 27 | } |
22 | 28 | } |
16 | 16 | } |
17 | 17 | |
18 | 18 | LinExp : UGen { |
19 | checkInputs { ^this.checkSameRateAsFirstInput } | |
19 | 20 | *ar { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; |
20 | 21 | ^this.multiNew('audio', in, srclo, srchi, dstlo, dsthi) |
21 | 22 | } |
25 | 26 | } |
26 | 27 | |
27 | 28 | LinLin : UGen { |
29 | checkInputs { ^this.checkSameRateAsFirstInput } | |
28 | 30 | *ar { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; |
29 | 31 | ^this.multiNew('audio', in, srclo, srchi, dstlo, dsthi) |
30 | 32 | } |
87 | 89 | |
88 | 90 | DC : MultiOutUGen { |
89 | 91 | *ar { arg in=0.0; |
90 | ^this.multiNewList(['audio'] ++ in) | |
92 | ^this.multiNew('audio', in) | |
91 | 93 | } |
92 | 94 | *kr { arg in=0.0; |
93 | ^this.multiNewList(['control'] ++ in) | |
95 | ^this.multiNew('control', in) | |
94 | 96 | } |
95 | 97 | init { arg ... argInputs; |
96 | 98 | inputs = argInputs; |
510 | 510 | }; |
511 | 511 | |
512 | 512 | // schedule when the bundles are sent |
513 | ||
514 | 513 | if (strum == 0) { |
515 | schedBundleArrayOnClock( | |
516 | offset, thisThread.clock, bndl, lag, server, ~latency); | |
514 | ~schedBundleArray.(lag, offset, server, bndl, ~latency); | |
517 | 515 | if (sendGate) { |
518 | schedBundleArrayOnClock( | |
519 | sustain + offset, thisThread.clock, | |
520 | [\n_set, ids, \gate, 0].flop, | |
521 | lag, server, ~latency | |
516 | ~schedBundleArray.( | |
517 | lag, | |
518 | sustain + offset, | |
519 | server, | |
520 | [\n_set, ids, \gate, 0].flop, | |
521 | ~latency | |
522 | 522 | ); |
523 | 523 | } |
524 | 524 | } { |
525 | ||
526 | 525 | if (strum < 0) { bndl = bndl.reverse }; |
527 | 526 | strumOffset = offset + Array.series(bndl.size, 0, strum.abs); |
528 | schedBundleArrayOnClock( | |
529 | strumOffset, thisThread.clock, bndl, | |
530 | lag, server, ~latency | |
527 | ~schedBundleArray.( | |
528 | lag, strumOffset, server, bndl, ~latency | |
531 | 529 | ); |
532 | 530 | if (sendGate) { |
533 | 531 | if (~strumEndsTogether) { |
535 | 533 | } { |
536 | 534 | strumOffset = sustain + strumOffset |
537 | 535 | }; |
538 | schedBundleArrayOnClock( | |
539 | strumOffset, thisThread.clock, | |
540 | [\n_set, ids, \gate, 0].flop, | |
541 | lag, server, ~latency | |
536 | ~schedBundleArray.( | |
537 | lag, strumOffset, server, | |
538 | [\n_set, ids, \gate, 0].flop, | |
539 | ~latency | |
542 | 540 | ); |
543 | 541 | } |
544 | 542 | } |
277 | 277 | ^this.as(Array).scramble.as(String) |
278 | 278 | } |
279 | 279 | |
280 | rotate { |n| | |
280 | rotate { arg n = 1; | |
281 | 281 | ^this.as(Array).rotate(n).as(String) |
282 | 282 | } |
283 | 283 |
0 | 0 | |
1 | 1 | + Server { |
2 | asBus { arg rate,numChannels; | |
2 | asBus { arg rate,numChannels=1; | |
3 | 3 | ^Bus.alloc(rate,this,numChannels) |
4 | 4 | } |
5 | 5 | } |
15 | 15 | } |
16 | 16 | |
17 | 17 | + Nil { |
18 | asBus { arg rate,numChannels,server; | |
18 | asBus { arg rate,numChannels=1,server; | |
19 | 19 | ^if(rate == \audio,{ |
20 | 20 | Bus(\audio,0,numChannels,server); // out yer speakers |
21 | 21 | },{ |
584 | 584 | var file; |
585 | 585 | dir = dir ? SynthDef.synthDefDir; |
586 | 586 | if (name.isNil) { error("missing SynthDef file name") } { |
587 | name = dir ++ name ++ ".scsyndef"; | |
587 | name = dir +/+ name ++ ".scsyndef"; | |
588 | 588 | if(overwrite or: { pathMatch(name).isEmpty }) |
589 | 589 | { |
590 | 590 | file = File(name, "w"); |
16 | 16 | var <>exceptionHandler; |
17 | 17 | var <executingPath, <oldExecutingPath; |
18 | 18 | |
19 | *new { arg func, stackSize=64; | |
19 | *new { arg func, stackSize=512; | |
20 | 20 | ^super.new.init(func, stackSize) |
21 | 21 | } |
22 | init { arg argFunc, argStackSize=64; | |
22 | init { arg argFunc, argStackSize=512; | |
23 | 23 | _Thread_Init |
24 | 24 | ^this.primitiveFailed |
25 | 25 | } |
120 | 120 | }); |
121 | 121 | } |
122 | 122 | |
123 | close { // close the file | |
123 | close { | |
124 | this.prClose; | |
125 | openFiles.remove(this); | |
126 | } | |
127 | ||
128 | prClose { // close the file | |
124 | 129 | // the GC will not call this for you |
125 | 130 | _PipeClose |
126 | 131 | ^this.primitiveFailed; |
408 | 408 | }, |
409 | 409 | methodTitle: { |v| v.string_("methods") }, |
410 | 410 | methodView: { |v| |
411 | ~methodView.items_(~classMethodNames ++ ~methodNames) | |
411 | var colorFunc = { |class, name| | |
412 | if(class.findOverriddenMethod(name.asSymbol).isNil) { | |
413 | Color.clear | |
414 | } { | |
415 | Color.grey(0.8) | |
416 | } | |
417 | }; | |
418 | var classMethodColors = ~classMethodNames.collect { |name| | |
419 | colorFunc.value(~currentClass.class, name) | |
420 | }; | |
421 | var methodColors = ~methodNames.collect { |name| | |
422 | colorFunc.value(~currentClass, name) | |
423 | }; | |
424 | var methodNames = ~classMethodNames ++ ~methodNames; | |
425 | var colors = classMethodColors ++ methodColors; | |
426 | ||
427 | ~methodView.items_(methodNames) | |
412 | 428 | .value_(~methodViewIndex ? 0) |
413 | 429 | .action_(~displayCurrentMethodArgsAction) |
414 | .mouseDownAction_(~listViewDoubleClickAction); | |
430 | .mouseDownAction_(~listViewDoubleClickAction) | |
431 | .tryPerform(\colors_, colors) | |
415 | 432 | }, |
416 | 433 | argView: { |v| |
417 | 434 | if (~currentMethod.isNil or: { ~currentMethod.argNames.isNil }) { |
0 | SCWindow { | |
1 | classvar <>allWindows, <currentFullScreen, <>initAction; | |
2 | ||
3 | var dataptr, <name, <>onClose, <view, <userCanClose=true; | |
4 | var <alwaysOnTop=false; | |
5 | var <>drawHook; | |
6 | var <acceptsMouseOver=false; | |
7 | var <isClosed = false; | |
8 | var <acceptsClickThrough = true; | |
9 | var <> toFrontAction, <> endFrontAction; | |
10 | var <editable=false, <>constructionView; | |
11 | var <currentSheet; // current modal sheet attached to this window, if it exists | |
12 | ||
13 | *initClass { | |
14 | UI.registerForShutdown({ this.closeAll }); | |
15 | } | |
16 | ||
17 | *new { arg name = "panel", bounds, resizable = true, border = true, server, scroll = false; | |
18 | ^super.new.initSCWindow(name, bounds, resizable, border, scroll) | |
19 | } | |
20 | // appmodal is a private flag used to disable the close button | |
21 | initSCWindow { arg argName, argBounds, resizable, border, scroll, appmodal = false; | |
22 | name = argName.asString; | |
23 | argBounds = argBounds ?? {Rect(128, 64, 400, 400)}; | |
24 | allWindows = allWindows.add(this); | |
25 | scroll.if({ | |
26 | view = SCScrollTopView(nil, argBounds.moveTo(0,0)); | |
27 | },{ | |
28 | view = SCTopView(nil, argBounds.moveTo(0,0)); | |
29 | }); | |
30 | this.prInit(name, argBounds, resizable, border, scroll, view, appmodal); | |
31 | initAction.value(this); | |
32 | } | |
33 | ||
34 | asView { ^view } | |
35 | add { arg aView; view.add(aView) } | |
36 | ||
37 | addFlowLayout { |margin, gap| | |
38 | view.relativeOrigin.if | |
39 | {view.decorator_( FlowLayout( view.bounds.moveTo(0,0), margin, gap ) )} | |
40 | {view.decorator_( FlowLayout( view.bounds, margin, gap ) )}; | |
41 | ^this.view.decorator; | |
42 | } | |
43 | ||
44 | *closeAll { | |
45 | var list; | |
46 | list = allWindows.copy; | |
47 | allWindows = Array.new(8); | |
48 | list.do({ arg window; window.close; }); | |
49 | } | |
50 | ||
51 | close { | |
52 | if (isClosed) { ^this }; | |
53 | this.prClose; | |
54 | } | |
55 | closed { | |
56 | isClosed = true; | |
57 | onClose.value; // call user function | |
58 | dataptr = nil; | |
59 | view.prClose; | |
60 | allWindows.remove(this); | |
61 | } | |
62 | ||
63 | addToOnClose { | function | onClose = onClose.addFunc(function) } | |
64 | ||
65 | removeFromOnClose { | function | onClose = onClose.removeFunc(function) } | |
66 | ||
67 | fullScreen { | |
68 | currentFullScreen.notNil.if({currentFullScreen.endFullScreen}); | |
69 | this.prFullScreen; | |
70 | currentFullScreen = this; | |
71 | } | |
72 | endFullScreen { | |
73 | this.prEndFullScreen; | |
74 | currentFullScreen = nil; | |
75 | } | |
76 | ||
77 | prFullScreen { | |
78 | _SCWindow_BeginFullScreen | |
79 | ^this.primitiveFailed | |
80 | } | |
81 | prEndFullScreen { | |
82 | _SCWindow_EndFullScreen | |
83 | ^this.primitiveFailed | |
84 | } | |
85 | userCanClose_ { arg boo; | |
86 | _SCWindow_SetShouldClose | |
87 | ^this.primitiveFailed | |
88 | } | |
89 | acceptsMouseOver_{arg bool; | |
90 | acceptsMouseOver = bool; | |
91 | this.prSetAcceptMouseOver(bool); | |
92 | } | |
93 | front { | |
94 | _SCWindow_ToFront | |
95 | ^this.primitiveFailed | |
96 | } | |
97 | ||
98 | alwaysOnTop_{|bool=true| | |
99 | alwaysOnTop = bool; | |
100 | this.prSetAlwaysOnTop(bool); | |
101 | } | |
102 | ||
103 | prSetAlwaysOnTop{|boolean=true| | |
104 | _SCWindow_AlwaysOnTop | |
105 | } | |
106 | ||
107 | acceptsClickThrough_{|boolean=true| | |
108 | acceptsClickThrough = boolean; | |
109 | this.prSetAcceptsClickThrough(boolean); | |
110 | } | |
111 | ||
112 | prSetAcceptsClickThrough{|boolean=true| | |
113 | _SCWindow_AcceptsClickThrough | |
114 | } | |
115 | ||
116 | refresh { | |
117 | _SCWindow_Refresh | |
118 | ^this.primitiveFailed | |
119 | } | |
120 | minimize { | |
121 | _SCWindow_Minimize | |
122 | ^this.primitiveFailed | |
123 | } | |
124 | alpha_ { arg alpha; | |
125 | _SCWindow_SetAlpha | |
126 | ^this.primitiveFailed | |
127 | } | |
128 | ||
129 | name_ { arg argName; | |
130 | name = argName; | |
131 | this.prSetName(argName); | |
132 | } | |
133 | // bounds are relative to the bottom left corner origin | |
134 | bounds_ { arg argBounds; | |
135 | this.prSetBounds(argBounds); | |
136 | } | |
137 | // set bounds relative to top left corner | |
138 | setTopLeftBounds { |rect,menuSpacer=45| | |
139 | rect = rect.copy; | |
140 | // 45 is the height of the mac os menu | |
141 | // if you are in full screen mode you would want to pass in 0 | |
142 | rect.top = SCWindow.screenBounds.height - rect.height - rect.top - menuSpacer; | |
143 | this.bounds = rect | |
144 | } | |
145 | setInnerExtent { arg w,h; // resize window keeping top left corner fixed | |
146 | var b; | |
147 | b = this.bounds; | |
148 | w = w ? b.width; | |
149 | h = h ? b.height; | |
150 | this.bounds = Rect(b.left,b.top + (b.height - h), w,h); | |
151 | } | |
152 | bounds { | |
153 | ^this.prGetBounds(Rect.new); | |
154 | } | |
155 | *screenBounds { | |
156 | ^this.prGetScreenBounds(Rect.new); | |
157 | } | |
158 | play { arg function; | |
159 | AppClock.play({ | |
160 | if (dataptr.notNil, { | |
161 | function.value; | |
162 | }); | |
163 | }); | |
164 | ||
165 | } | |
166 | ||
167 | findByID { arg id; | |
168 | ^view.findByID(id) | |
169 | } | |
170 | ||
171 | // PRIVATE | |
172 | // primitives | |
173 | prInit { arg argName, argBounds, resizable, border, scroll, view, appmodal = false; | |
174 | _SCWindow_New | |
175 | ^this.primitiveFailed | |
176 | } | |
177 | prClose { | |
178 | _SCWindow_Close | |
179 | ^this.primitiveFailed | |
180 | } | |
181 | prSetName { arg argName; | |
182 | _SCWindow_SetName | |
183 | ^this.primitiveFailed | |
184 | } | |
185 | prGetBounds { arg argBounds; | |
186 | _SCWindow_GetBounds | |
187 | ^this.primitiveFailed | |
188 | } | |
189 | prSetBounds { arg argBounds; | |
190 | _SCWindow_SetBounds | |
191 | ^this.primitiveFailed | |
192 | } | |
193 | prSetAcceptMouseOver{arg bool; | |
194 | _SCWindow_SetAcceptMouseOver | |
195 | ^this.primitiveFailed | |
196 | } | |
197 | *prGetScreenBounds { arg argBounds; | |
198 | _SCWindow_GetScreenBounds | |
199 | ^this.primitiveFailed | |
200 | } | |
201 | callDrawHook { | |
202 | drawHook.value(this); | |
203 | } | |
204 | ||
205 | didBecomeKey { | |
206 | toFrontAction.value(this); | |
207 | } | |
208 | ||
209 | didResignKey { | |
210 | endFrontAction.value(this); | |
211 | } | |
212 | ||
213 | toggleEditMode{ | |
214 | var panel; | |
215 | editable = editable.not; | |
216 | if(editable){ | |
217 | SCIBToolboxWindow.front.addWindow(this); | |
218 | this.refresh; | |
219 | }{ | |
220 | SCIBToolboxWindow.front.removeWindow(this); | |
221 | } | |
222 | } | |
223 | setCurrentSheet {|sheet| currentSheet = sheet;} | |
224 | /* | |
225 | *viewPalette {|win| | |
226 | var w, v, f, c; | |
227 | w = SCWindow("View Palette", Rect(532, 64, 300, 320), scroll: true).front; | |
228 | w.view.decorator = f = FlowLayout(w.view.bounds); | |
229 | SCButton(w, 300@20).states_([ ["-> CODE"]]) | |
230 | .canFocus_(false).action_{ | |
231 | Document("window construction code", win.asConstructionCompileString); | |
232 | }; | |
233 | w.view.decorator.nextLine; | |
234 | // c = [SCSlider, SCRangeSlider, SC2DSlider, SCPopUpMenu, SCButton, | |
235 | // SCNumberBox, SCMultiSliderView, | |
236 | // SCStaticText, SCDragSource, SCDragSink, SCDragBoth, | |
237 | // ]; | |
238 | c = SCView.allSubclasses.reject{|it| | |
239 | (it.superclasses.indexOf(SCContainerView).notNil | |
240 | or: (it.name === 'SCContainerView') | |
241 | or: (it.name ==='SCStaticTextBase') | |
242 | or: (it.name === 'SCSliderBase') | |
243 | or: (it.name === 'SCControlView')) | |
244 | }; | |
245 | ||
246 | c.do({ arg item; | |
247 | var n; | |
248 | n = SCDragSource(w, Rect(0, 0, 140, 24)); | |
249 | n.object = item; | |
250 | ||
251 | try{ | |
252 | item.paletteExample(w, Rect(0,0,140,24)); | |
253 | }{ | |
254 | "no paletteExample found".warn; | |
255 | }; | |
256 | w.view.decorator.nextLine; | |
257 | ||
258 | }); | |
259 | win.onClose_{ | |
260 | Document("window construction code", win.asConstructionCompileString); | |
261 | w.close | |
262 | }; | |
263 | ^w | |
264 | } | |
265 | */ | |
266 | ||
267 | storeArgs{^[name, this.bounds]} | |
268 | storeModifiersOn{|stream| | |
269 | stream << ".front;"; | |
270 | } | |
271 | } | |
272 |
0 | SCFont { | |
1 | classvar <>default; | |
2 | var <>name, <>size; | |
3 | ||
4 | *new { arg name, size; | |
5 | ^super.newCopyArgs(name, size); | |
6 | } | |
7 | setDefault { default = this } | |
8 | ||
9 | *availableFonts { | |
10 | // returns an Array of font names. | |
11 | _Font_AvailableFonts | |
12 | ^this.primitiveFailed | |
13 | } | |
14 | *antiAliasing_ { arg flag = false; | |
15 | _Font_SetAntiAliasing; | |
16 | ^this.primitiveFailed | |
17 | } | |
18 | *smoothing_ { arg flag = false; | |
19 | _Font_SetSmoothing; | |
20 | ^this.primitiveFailed | |
21 | } | |
22 | storeArgs { ^[name,size] } | |
23 | ||
24 | boldVariant { | |
25 | ^if( name.endsWith( "-Bold" ), this, { this.class.new( name ++ "-Bold", size )}); | |
26 | } | |
27 | ||
28 | *defaultSansFace { | |
29 | ^"Helvetica"; | |
30 | } | |
31 | ||
32 | *defaultSerifFace { | |
33 | ^"Times"; | |
34 | } | |
35 | ||
36 | *defaultMonoFace { | |
37 | ^"Monaco"; | |
38 | } | |
39 | }⏎ |
0 | ||
1 | SCView { // abstract class | |
2 | classvar <>currentDrag, <>currentDragString; | |
3 | classvar <>globalKeyDownAction, <>globalKeyUpAction; | |
4 | ||
5 | var dataptr, <parent, <>action, <background; | |
6 | var <>mouseDownAction, <>mouseUpAction, <>mouseOverAction, <>mouseMoveAction; | |
7 | var <>keyDownAction, <>keyUpAction, <>keyTyped, <> keyModifiersChangedAction; | |
8 | var <>beginDragAction,<>canReceiveDragHandler,<>receiveDragHandler; | |
9 | var <>onClose; | |
10 | ||
11 | *new { arg parent, bounds; | |
12 | ^super.new.init(parent, bounds); | |
13 | } | |
14 | *viewClass { ^this } | |
15 | *paletteExample { arg parent, bounds; | |
16 | ^this.new(parent, bounds); | |
17 | } | |
18 | ||
19 | init { arg argParent, argBounds; | |
20 | parent = argParent.asView; // actual view | |
21 | background = Color.clear; | |
22 | // call asView again because parent by this point might be a FlowView | |
23 | this.prInit(parent.asView, argBounds.asRect,this.class.viewClass); | |
24 | argParent.add(this);//maybe window or viewadapter | |
25 | } | |
26 | ||
27 | asView { ^this } | |
28 | ||
29 | bounds { | |
30 | ^this.getProperty(\bounds, Rect.new) | |
31 | } | |
32 | bounds_ { arg rect; | |
33 | this.setProperty(\bounds, rect) | |
34 | } | |
35 | ||
36 | visible { | |
37 | ^this.getProperty(\visible) | |
38 | } | |
39 | visible_ { arg bool; | |
40 | this.setProperty(\visible, bool) | |
41 | } | |
42 | ||
43 | enabled { | |
44 | ^this.getProperty(\enabled) | |
45 | } | |
46 | enabled_ { arg bool; | |
47 | this.setProperty(\enabled, bool) | |
48 | } | |
49 | ||
50 | canFocus { | |
51 | ^this.getProperty(\canFocus) | |
52 | } | |
53 | canFocus_ { arg bool; | |
54 | this.setProperty(\canFocus, bool) | |
55 | } | |
56 | focus { arg flag=true; | |
57 | _SCView_Focus | |
58 | ^this.primitiveFailed | |
59 | } | |
60 | hasFocus{ | |
61 | _SCView_HasFocus | |
62 | ^this.primitiveFailed | |
63 | } | |
64 | ||
65 | focusColor_{|color| | |
66 | this.setProperty(\focusColor, color); | |
67 | } | |
68 | ||
69 | focusColor{ | |
70 | ^this.getProperty(\focusColor, Color.new); | |
71 | } | |
72 | ||
73 | id { | |
74 | ^this.getProperty(\id) | |
75 | } | |
76 | id_ { arg id; | |
77 | this.setProperty(\id, id) | |
78 | } | |
79 | ||
80 | dragLabel_ { arg string; | |
81 | this.setProperty(\dragLabel, string) | |
82 | } | |
83 | ||
84 | refresh { | |
85 | _SCView_Refresh | |
86 | ^this.primitiveFailed | |
87 | } | |
88 | findByID { arg id; | |
89 | _SCView_FindByID | |
90 | ^this.primitiveFailed | |
91 | } | |
92 | ||
93 | isClosed { ^dataptr.isNil } | |
94 | notClosed { ^dataptr.notNil } | |
95 | remove { | |
96 | if(dataptr.notNil,{ | |
97 | parent.prRemoveChild(this); | |
98 | this.prRemove; | |
99 | this.prClose; | |
100 | },{ | |
101 | "SCView-remove : this view already removed.".debug(this); | |
102 | }); | |
103 | } | |
104 | /* | |
105 | resize behaviour in an SCCompositeView: | |
106 | 1 2 3 | |
107 | 4 5 6 | |
108 | 7 8 9 | |
109 | ||
110 | 1 - fixed to left, fixed to top | |
111 | 2 - horizontally elastic, fixed to top | |
112 | 3 - fixed to right, fixed to top | |
113 | ||
114 | 4 - fixed to left, vertically elastic | |
115 | 5 - horizontally elastic, vertically elastic | |
116 | 6 - fixed to right, vertically elastic | |
117 | ||
118 | 7 - fixed to left, fixed to bottom | |
119 | 8 - horizontally elastic, fixed to bottom | |
120 | 9 - fixed to right, fixed to bottom | |
121 | */ | |
122 | resize { | |
123 | ^this.getProperty(\resize) | |
124 | } | |
125 | resize_ { arg resize; | |
126 | this.setProperty(\resize, resize) | |
127 | } | |
128 | ||
129 | background_ { arg color; | |
130 | background = color; | |
131 | this.setProperty(\background, color) | |
132 | } | |
133 | addAction { arg func, selector=\action; | |
134 | this.perform(selector.asSetter, this.perform(selector).addFunc(func)); | |
135 | } | |
136 | removeAction { arg func, selector=\action; | |
137 | this.perform(selector.asSetter, this.perform(selector).removeFunc(func)); | |
138 | } | |
139 | mouseDown{arg x, y, modifiers, buttonNumber, clickCount; | |
140 | mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount); | |
141 | } | |
142 | mouseUp{arg x, y, modifiers; | |
143 | mouseUpAction.value(this, x, y, modifiers); | |
144 | } | |
145 | mouseMove{arg x, y, modifiers; | |
146 | mouseMoveAction.value(this, x, y, modifiers); | |
147 | } | |
148 | mouseOver{arg x, y; | |
149 | mouseOverAction.value(this, x, y); | |
150 | } | |
151 | ||
152 | keyDown { arg char, modifiers, unicode,keycode; | |
153 | globalKeyDownAction.value(this, char, modifiers, unicode, keycode); | |
154 | this.handleKeyDownBubbling(this, char, modifiers, unicode, keycode); | |
155 | } | |
156 | ||
157 | keyModifiersChanged{arg modifiers; | |
158 | this.handleKeyModifiersChangedBubbling(this,modifiers) | |
159 | } | |
160 | ||
161 | handleKeyModifiersChangedBubbling { arg view, modifiers; | |
162 | var result; | |
163 | // nil from keyDownAction --> pass it on | |
164 | if (keyModifiersChangedAction.isNil) { | |
165 | // this.defaultKeyDownAction(char,modifiers,unicode,keycode); | |
166 | result = nil; | |
167 | }{ | |
168 | result = keyModifiersChangedAction.value(view, modifiers); | |
169 | }; | |
170 | if(result.isNil) { | |
171 | // call keydown action of parent view | |
172 | parent.handleKeyModifiersChangedBubbling(view, modifiers); | |
173 | }; | |
174 | } | |
175 | ||
176 | defaultKeyDownAction { ^nil } | |
177 | handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode; | |
178 | var result; | |
179 | // nil from keyDownAction --> pass it on | |
180 | if (keyDownAction.isNil) { | |
181 | result = this.defaultKeyDownAction(char,modifiers,unicode,keycode); | |
182 | }{ | |
183 | result = keyDownAction.value(view, char, modifiers, unicode, keycode); | |
184 | }; | |
185 | if(result.isNil) { | |
186 | // call keydown action of parent view | |
187 | parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode); | |
188 | }; | |
189 | } | |
190 | ||
191 | // sc.solar addition | |
192 | keyUp { arg char, modifiers, unicode,keycode; | |
193 | this.keyTyped = char; | |
194 | // always call global keydown action first | |
195 | globalKeyUpAction.value(this, char, modifiers, unicode, keycode); | |
196 | this.handleKeyUpBubbling(this, char, modifiers, unicode, keycode); | |
197 | } | |
198 | defaultKeyUpAction { ^nil } | |
199 | handleKeyUpBubbling { arg view, char, modifiers,unicode,keycode; | |
200 | var result; | |
201 | // nil from keyDownAction --> pass it on | |
202 | if (keyUpAction.isNil) { | |
203 | result = this.defaultKeyUpAction(char,modifiers,unicode,keycode); | |
204 | }{ | |
205 | result = keyUpAction.value(view, char, modifiers, unicode, keycode); | |
206 | }; | |
207 | if(result.isNil) { | |
208 | // call keydown action of parent view | |
209 | parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode); | |
210 | }; | |
211 | } | |
212 | ||
213 | ||
214 | beginDrag { | |
215 | currentDrag = if (beginDragAction.notNil) | |
216 | { | |
217 | beginDragAction.value(this) | |
218 | }{ | |
219 | this.defaultGetDrag | |
220 | }; | |
221 | currentDragString = currentDrag.asCompileString; | |
222 | } | |
223 | defaultGetDrag { ^nil } | |
224 | canReceiveDrag { | |
225 | ^if(canReceiveDragHandler.notNil,{ canReceiveDragHandler.value(this) },{ this.defaultCanReceiveDrag }) | |
226 | } | |
227 | defaultCanReceiveDrag { ^false } | |
228 | receiveDrag {|x,y| | |
229 | if(receiveDragHandler.notNil,{ receiveDragHandler.value(this, x, y) },{ this.defaultReceiveDrag(x,y) }); | |
230 | currentDrag = currentDragString = nil; | |
231 | } | |
232 | ||
233 | // get the view parent tree up to the SCTopView | |
234 | getParents { | |
235 | var parents, view; | |
236 | view = this; | |
237 | parents = List.new; | |
238 | while({(view = view.parent).notNil},{ parents.add(view)}); | |
239 | ^parents | |
240 | } | |
241 | ||
242 | doAction { | |
243 | action.value(this); | |
244 | } | |
245 | ||
246 | properties { | |
247 | ^#[\bounds, \visible, \enabled, \canFocus, \resize, \background, | |
248 | \minWidth,\maxWidth,\minHeight,\maxHeight,\focusColor] | |
249 | } | |
250 | getPropertyList { | |
251 | ^this.properties.collect({ arg name; | |
252 | [name, this.perform(name)] | |
253 | }); | |
254 | } | |
255 | setPropertyList { arg list; | |
256 | list.do({ arg item; | |
257 | var name, value; | |
258 | #name, value = item; | |
259 | this.perform(name.asSetter, value); | |
260 | }); | |
261 | } | |
262 | ||
263 | // private | |
264 | prInit { arg argParent, argBounds,argViewClass; | |
265 | _SCView_New | |
266 | ^this.primitiveFailed | |
267 | } | |
268 | prClose { dataptr = nil; onClose.value(this); } | |
269 | prRemove { | |
270 | _SCView_Remove | |
271 | ^this.primitiveFailed | |
272 | } | |
273 | setProperty { arg key, value; | |
274 | _SCView_SetProperty | |
275 | ^this.primitiveFailed | |
276 | } | |
277 | getProperty { arg key, value; | |
278 | _SCView_GetProperty | |
279 | ^this.primitiveFailed | |
280 | } | |
281 | setPropertyWithAction { arg symbol, obj; | |
282 | // setting some properties may need to have the action called. | |
283 | if (this.setProperty(symbol, obj), { | |
284 | // setProperty returns true if action needs to be called. | |
285 | this.doAction; | |
286 | }); | |
287 | } | |
288 | ||
289 | // *importDrag { | |
290 | // // this is called when an NSString is the drag object | |
291 | // // from outside of the SC app | |
292 | // // we compile it to an SCObject. | |
293 | // currentDragString = currentDrag; | |
294 | // currentDrag = currentDrag.interpret; | |
295 | // } | |
296 | ||
297 | absoluteBounds { | |
298 | ^this.getProperty(\absoluteBounds,Rect.new) | |
299 | } | |
300 | } | |
301 | ||
302 | SCContainerView : SCView { // abstract class | |
303 | var <children, <decorator, < relativeOrigin = true; | |
304 | ||
305 | add { arg child; | |
306 | children = children.add(child); | |
307 | if (decorator.notNil, { decorator.place(child); }); | |
308 | } | |
309 | ||
310 | init { |argParent, argBounds| | |
311 | super.init(argParent, argBounds); | |
312 | // if user changed default relativeOrigin to true, | |
313 | // the client would be out of sync with the cocoa widget | |
314 | // without resetting the view property | |
315 | this.relativeOrigin = relativeOrigin; | |
316 | } | |
317 | ||
318 | removeAll { | |
319 | children.copy.do {|child| child.remove }; | |
320 | } | |
321 | ||
322 | relativeOrigin_{ |bool| | |
323 | relativeOrigin = bool; | |
324 | this.setProperty(\relativeOrigin, bool); | |
325 | } | |
326 | ||
327 | addFlowLayout { |margin, gap| | |
328 | this.relativeOrigin.if | |
329 | {this.decorator_( FlowLayout( this.bounds.moveTo(0,0), margin, gap ) )} | |
330 | {this.decorator_( FlowLayout( this.bounds, margin, gap ) )}; | |
331 | ^this.decorator; | |
332 | } | |
333 | ||
334 | decorator_ {|decor| | |
335 | if(relativeOrigin, { | |
336 | decor.bounds = decor.bounds.moveTo(0, 0); | |
337 | decor.reset; | |
338 | }); | |
339 | decorator = decor; | |
340 | } | |
341 | ||
342 | prRemoveChild { arg child; | |
343 | children.remove(child); | |
344 | // ... decorator should re-place all | |
345 | } | |
346 | ||
347 | //bounds_ ... replace all | |
348 | ||
349 | prClose { | |
350 | super.prClose; | |
351 | children.do({ arg item; item.prClose }); | |
352 | } | |
353 | } | |
354 | ||
355 | SCCompositeView : SCContainerView { | |
356 | } | |
357 | ||
358 | SCTopView : SCCompositeView { | |
359 | // created by SCWindow | |
360 | handleKeyModifiersChangedBubbling { arg view, modifiers; | |
361 | keyModifiersChangedAction.value(view, modifiers); | |
362 | } | |
363 | handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode; | |
364 | var currentAppModal, window; | |
365 | keyDownAction.value(view, char, modifiers, unicode, keycode); | |
366 | } | |
367 | handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode; | |
368 | keyUpAction.value(view, char, modifiers, unicode, keycode); | |
369 | } | |
370 | ||
371 | //only in construction mode, handled internally | |
372 | canReceiveDrag { ^currentDrag.isKindOf(Class)} | |
373 | // remove { this.removeAll } | |
374 | ||
375 | findWindow{ | |
376 | SCWindow.allWindows.do {|win| | |
377 | if(win.view == this){ | |
378 | ^win | |
379 | } | |
380 | } | |
381 | } | |
382 | ||
383 | /* construction mode */ | |
384 | ||
385 | constructionGrid_{ arg point; | |
386 | this.setProperty( \constructionGrid, point ); | |
387 | } | |
388 | ||
389 | constructionGrid { | |
390 | ^this.getProperty( \constructionGrid, Point.new ); | |
391 | } | |
392 | ||
393 | enableConstructionGrid_{arg flag; | |
394 | this.setProperty( \enableConstructionGrid, flag ); | |
395 | } | |
396 | ||
397 | enableConstructionGrid{ | |
398 | ^this.getProperty( \enableConstructionGrid ); | |
399 | } | |
400 | ||
401 | //private called from lang | |
402 | setConstructionMode {|flag| | |
403 | this.setProperty( \setConstructionMode, flag ) | |
404 | } | |
405 | ||
406 | defaultReceiveDrag{|x,y| | |
407 | var win, view; | |
408 | win = this.findWindow; | |
409 | view = currentDrag.paletteExample(win, Rect(x,y,140,24)).enabled_(false); | |
410 | view.keyDownAction_({|view, char, modifiers, unicode, keycode| | |
411 | if(keycode == 51){ | |
412 | view.remove; | |
413 | } | |
414 | }); | |
415 | } | |
416 | } | |
417 | ||
418 | SCScrollTopView : SCTopView { | |
419 | var <autohidesScrollers = true, <hasHorizontalScroller = true, <hasVerticalScroller = true; | |
420 | var <autoScrolls = true; | |
421 | ||
422 | autohidesScrollers_{|bool| | |
423 | autohidesScrollers = bool; | |
424 | this.setProperty(\setAutohidesScrollers, bool); | |
425 | } | |
426 | ||
427 | hasHorizontalScroller_{|bool| | |
428 | hasHorizontalScroller = bool; | |
429 | this.setProperty(\setHasHorizontalScroller, bool); | |
430 | } | |
431 | ||
432 | hasVerticalScroller_{|bool| | |
433 | hasVerticalScroller = bool; | |
434 | this.setProperty(\setHasVerticalScroller, bool); | |
435 | } | |
436 | ||
437 | visibleOrigin_ { arg point; | |
438 | this.setProperty( \clipViewOrigin, point ); | |
439 | } | |
440 | ||
441 | visibleOrigin { ^this.getProperty( \clipViewOrigin, Point.new );} | |
442 | ||
443 | autoScrolls_ {|bool| | |
444 | autoScrolls = bool; | |
445 | this.setProperty(\setAutoScrolls, bool); | |
446 | } | |
447 | ||
448 | innerBounds { | |
449 | ^this.getProperty(\innerBounds, Rect.new) | |
450 | } | |
451 | ||
452 | bounds { | |
453 | var bounds = this.absoluteBounds; | |
454 | this.getParents.do({ |parent| | |
455 | (parent.tryPerform(\relativeOrigin) == true).if({ | |
456 | bounds = bounds.moveBy(parent.bounds.left.neg, parent.bounds.top.neg) | |
457 | }, { | |
458 | ^bounds | |
459 | }); | |
460 | }); | |
461 | ^bounds | |
462 | } | |
463 | ||
464 | // handleKeyModifiersChangedBubbling { arg view, modifiers; | |
465 | // var result; | |
466 | // // nil from keyDownAction --> pass it on | |
467 | // if (keyModifiersChangedAction.isNil) { | |
468 | // result = nil; | |
469 | // }{ | |
470 | // result = keyModifiersChangedAction.value(view, modifiers); | |
471 | // }; | |
472 | // if(result.isNil) { | |
473 | // // call keydown action of parent view | |
474 | // parent.handleKeyModifiersChangedBubbling(view, modifiers); | |
475 | // }; | |
476 | // } | |
477 | // | |
478 | // handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode; | |
479 | // var result; | |
480 | // // nil from keyDownAction --> pass it on | |
481 | // if (keyDownAction.isNil) { | |
482 | // result = this.defaultKeyDownAction(char,modifiers,unicode,keycode); | |
483 | // }{ | |
484 | // result = keyDownAction.value(view, char, modifiers, unicode, keycode); | |
485 | // }; | |
486 | // if(result.isNil) { | |
487 | // // call keydown action of parent view | |
488 | // parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode); | |
489 | // }; | |
490 | // } | |
491 | // | |
492 | // handleKeyUpBubbling { arg view, char, modifiers,unicode,keycode; | |
493 | // var result; | |
494 | // // nil from keyDownAction --> pass it on | |
495 | // if (keyUpAction.isNil) { | |
496 | // result = this.defaultKeyUpAction(char,modifiers,unicode,keycode); | |
497 | // }{ | |
498 | // result = keyUpAction.value(view, char, modifiers, unicode, keycode); | |
499 | // }; | |
500 | // if(result.isNil) { | |
501 | // // call keydown action of parent view | |
502 | // parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode); | |
503 | // }; | |
504 | // } | |
505 | ||
506 | } | |
507 | ||
508 | SCScrollView : SCScrollTopView { | |
509 | var <hasBorder = false; | |
510 | ||
511 | hasBorder_ { arg bool = true; | |
512 | this.setProperty(\border, bool); | |
513 | } | |
514 | ||
515 | init { |argParent, argBounds| | |
516 | super.init(argParent, argBounds); | |
517 | ||
518 | relativeOrigin = false; // scroll views are never relative, although they really are ;-) | |
519 | } | |
520 | ||
521 | relativeOrigin_ { } | |
522 | ||
523 | handleKeyModifiersChangedBubbling { arg view, modifiers; | |
524 | var result; | |
525 | // nil from keyDownAction --> pass it on | |
526 | if (keyModifiersChangedAction.isNil) { | |
527 | result = nil; | |
528 | }{ | |
529 | result = keyModifiersChangedAction.value(view, modifiers); | |
530 | }; | |
531 | if(result.isNil) { | |
532 | // call keydown action of parent view | |
533 | parent.handleKeyModifiersChangedBubbling(view, modifiers); | |
534 | }; | |
535 | } | |
536 | ||
537 | handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode; | |
538 | var result; | |
539 | // nil from keyDownAction --> pass it on | |
540 | if (keyDownAction.isNil) { | |
541 | result = this.defaultKeyDownAction(char,modifiers,unicode,keycode); | |
542 | }{ | |
543 | result = keyDownAction.value(view, char, modifiers, unicode, keycode); | |
544 | }; | |
545 | if(result.isNil) { | |
546 | // call keydown action of parent view | |
547 | parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode); | |
548 | }; | |
549 | } | |
550 | ||
551 | handleKeyUpBubbling { arg view, char, modifiers,unicode,keycode; | |
552 | var result; | |
553 | // nil from keyDownAction --> pass it on | |
554 | if (keyUpAction.isNil) { | |
555 | result = this.defaultKeyUpAction(char,modifiers,unicode,keycode); | |
556 | }{ | |
557 | result = keyUpAction.value(view, char, modifiers, unicode, keycode); | |
558 | }; | |
559 | if(result.isNil) { | |
560 | // call keydown action of parent view | |
561 | parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode); | |
562 | }; | |
563 | } | |
564 | ||
565 | } | |
566 | ||
567 | SCLayoutView : SCContainerView { | |
568 | properties { ^super.properties ++ #[\spacing] } | |
569 | ||
570 | spacing { | |
571 | ^this.getProperty(\spacing, 0) | |
572 | } | |
573 | spacing_ { arg distance; | |
574 | this.setProperty(\spacing, distance) | |
575 | } | |
576 | setProperty { |key, value| | |
577 | // layout views don't recognize relativeOrigin in the backend | |
578 | if(key != \relativeOrigin) { | |
579 | super.setProperty(key, value); | |
580 | }; | |
581 | } | |
582 | } | |
583 | ||
584 | SCHLayoutView : SCLayoutView {} | |
585 | SCVLayoutView : SCLayoutView {} | |
586 | ||
587 | ||
588 | SCControlView : SCView { // abstract class | |
589 | } | |
590 | ||
591 | SCSliderBase : SCControlView { | |
592 | ||
593 | knobColor { | |
594 | ^this.getProperty(\knobColor, Color.new) | |
595 | } | |
596 | knobColor_ { arg color; | |
597 | this.setProperty(\knobColor, color) | |
598 | } | |
599 | ||
600 | step_ { arg stepSize; | |
601 | this.setPropertyWithAction(\step, stepSize); | |
602 | } | |
603 | step { | |
604 | ^this.getProperty(\step) | |
605 | } | |
606 | ||
607 | properties { | |
608 | ^super.properties ++ #[\knobColor, \step] | |
609 | } | |
610 | ||
611 | } | |
612 | ||
613 | SCSlider : SCSliderBase | |
614 | { | |
615 | value { | |
616 | ^this.getProperty(\value) | |
617 | } | |
618 | value_ { arg val; | |
619 | this.setProperty(\value, val); | |
620 | } | |
621 | valueAction_ { arg val; | |
622 | this.setPropertyWithAction(\value, val); | |
623 | } | |
624 | ||
625 | increment { |zoom=1| ^this.valueAction = this.value + (max(this.step, this.pixelStep) * zoom) } | |
626 | decrement { |zoom=1| ^this.valueAction = this.value - (max(this.step, this.pixelStep) * zoom) } | |
627 | ||
628 | pixelStep { | |
629 | var bounds = this.bounds; | |
630 | ^(bounds.width.max(bounds.height) - this.thumbSize).reciprocal | |
631 | } | |
632 | ||
633 | defaultKeyDownAction { arg char, modifiers, unicode,keycode; | |
634 | // standard keydown | |
635 | if (char == $r, { this.valueAction = 1.0.rand; ^this }); | |
636 | if (char == $n, { this.valueAction = 0.0; ^this }); | |
637 | if (char == $x, { this.valueAction = 1.0; ^this }); | |
638 | if (char == $c, { this.valueAction = 0.5; ^this }); | |
639 | if (char == $], { this.increment; ^this }); | |
640 | if (char == $[, { this.decrement; ^this }); | |
641 | if (unicode == 16rF700, { this.increment; ^this }); | |
642 | if (unicode == 16rF703, { this.increment; ^this }); | |
643 | if (unicode == 16rF701, { this.decrement; ^this }); | |
644 | if (unicode == 16rF702, { this.decrement; ^this }); | |
645 | ^nil // bubble if it's an invalid key | |
646 | } | |
647 | ||
648 | defaultGetDrag { | |
649 | ^this.value | |
650 | } | |
651 | defaultCanReceiveDrag { | |
652 | ^currentDrag.isNumber | |
653 | } | |
654 | defaultReceiveDrag { | |
655 | this.valueAction = currentDrag; | |
656 | } | |
657 | ||
658 | thumbSize { | |
659 | ^this.getProperty(\thumbSize, 12); | |
660 | } | |
661 | thumbSize_ { arg size; | |
662 | this.setProperty(\thumbSize, size); | |
663 | } | |
664 | ||
665 | properties { | |
666 | ^super.properties ++ #[\thumbSize]; | |
667 | } | |
668 | } | |
669 | ||
670 | SCRangeSlider : SCSliderBase { | |
671 | ||
672 | *paletteExample { arg parent, bounds; | |
673 | var v; | |
674 | v = this.new(parent, bounds); | |
675 | v.lo = 0.2; | |
676 | v.hi = 0.7; | |
677 | ^v | |
678 | } | |
679 | ||
680 | lo { | |
681 | ^this.getProperty(\lo) | |
682 | } | |
683 | lo_ { arg val; | |
684 | this.setProperty(\lo, val); | |
685 | } | |
686 | activeLo_ { arg val; | |
687 | this.setPropertyWithAction(\lo, val); | |
688 | } | |
689 | hi { | |
690 | ^this.getProperty(\hi) | |
691 | } | |
692 | hi_ { arg val; | |
693 | this.setProperty(\hi, val); | |
694 | } | |
695 | activeHi_ { arg val; | |
696 | this.setPropertyWithAction(\hi, val); | |
697 | } | |
698 | range { | |
699 | ^this.getProperty(\range) | |
700 | } | |
701 | range_ { arg val; | |
702 | this.setProperty(\range, val); | |
703 | } | |
704 | activeRange_ { arg val; | |
705 | this.setPropertyWithAction(\range, val); | |
706 | } | |
707 | ||
708 | setSpan { arg lo, hi; | |
709 | this.lo = lo; | |
710 | this.hi = hi; | |
711 | } | |
712 | ||
713 | setSpanActive { arg lo, hi; | |
714 | this.setSpan( lo, hi ); | |
715 | this.doAction; | |
716 | } | |
717 | ||
718 | setDeviation { arg deviation, average; | |
719 | var lo = ( 1 - deviation ) * average; | |
720 | this.setSpan(lo, lo + deviation); | |
721 | } | |
722 | ||
723 | properties { | |
724 | ^super.properties ++ #[\lo, \hi] | |
725 | } | |
726 | ||
727 | pixelStep { | |
728 | var bounds = this.bounds; | |
729 | ^(bounds.width.max(bounds.height)).reciprocal | |
730 | } | |
731 | ||
732 | increment { |zoom=1| | |
733 | var inc = (max(this.step, this.pixelStep) * zoom); | |
734 | var newHi = (this.hi + inc); | |
735 | if (newHi > 1) { | |
736 | inc = 1 - this.hi; | |
737 | newHi = 1; | |
738 | }; | |
739 | this.lo_(this.lo + inc).activeHi_(newHi); | |
740 | } | |
741 | ||
742 | decrement { |zoom=1| | |
743 | var inc = (max(this.step, this.pixelStep) * zoom); | |
744 | var newLo = (this.lo - inc); | |
745 | if (newLo < 0) { | |
746 | inc = this.lo; | |
747 | newLo = 0; | |
748 | }; | |
749 | this.lo_(newLo).activeHi_(this.hi - inc); | |
750 | } | |
751 | ||
752 | defaultKeyDownAction { arg char, modifiers, unicode; | |
753 | var a, b; | |
754 | // standard keydown | |
755 | if (char == $r, { | |
756 | a = 1.0.rand; | |
757 | b = 1.0.rand; | |
758 | this.activeLo_(min(a, b)); | |
759 | this.activeHi_(max(a, b)); | |
760 | ^this | |
761 | }); | |
762 | if (char == $n, { this.activeLo_(0.0); this.activeHi_(0.0); ^this }); | |
763 | if (char == $x, { this.activeLo_(1.0); this.activeHi_(1.0); ^this }); | |
764 | if (char == $c, { this.activeLo_(0.5); this.activeHi_(0.5); ^this }); | |
765 | if (char == $a, { this.activeLo_(0.0); this.activeHi_(1.0); ^this }); | |
766 | if (unicode == 16rF700, { this.increment; ^this }); | |
767 | if (unicode == 16rF703, { this.increment; ^this }); | |
768 | if (unicode == 16rF701, { this.decrement; ^this }); | |
769 | if (unicode == 16rF702, { this.decrement; ^this }); | |
770 | ^nil // bubble if it's an invalid key | |
771 | } | |
772 | defaultGetDrag { ^Point(this.lo, this.hi) } | |
773 | defaultCanReceiveDrag { | |
774 | ^currentDrag.isKindOf(Point); | |
775 | } | |
776 | defaultReceiveDrag { | |
777 | // changed to x,y instead of lo, hi | |
778 | this.lo = currentDrag.x; | |
779 | this.hi = currentDrag.y; | |
780 | this.doAction | |
781 | } | |
782 | } | |
783 | ||
784 | SCButton : SCControlView { | |
785 | var <font, <states; | |
786 | ||
787 | *paletteExample { arg parent, bounds; | |
788 | var v; | |
789 | v = this.new(parent, bounds); | |
790 | v.states = [ | |
791 | ["Push", Color.black, Color.red], | |
792 | ["Pop", Color.white, Color.blue]]; | |
793 | ^v | |
794 | } | |
795 | ||
796 | value { | |
797 | ^this.getProperty(\value) | |
798 | } | |
799 | value_ { arg val; | |
800 | this.setProperty(\value, val); | |
801 | } | |
802 | valueAction_ { arg val; | |
803 | this.setPropertyWithAction(\value, val); | |
804 | } | |
805 | ||
806 | doAction { arg modifiers; | |
807 | action.value(this, modifiers); | |
808 | } | |
809 | ||
810 | defaultKeyDownAction { arg char, modifiers, unicode; | |
811 | if (char == $ , { this.valueAction = this.value + 1; ^this }); | |
812 | if (char == $\r, { this.valueAction = this.value + 1; ^this }); | |
813 | if (char == $\n, { this.valueAction = this.value + 1; ^this }); | |
814 | if (char == 3.asAscii, { this.valueAction = this.value + 1; ^this }); | |
815 | ^nil // bubble if it's an invalid key | |
816 | } | |
817 | ||
818 | font_ { arg argFont; | |
819 | font = argFont; | |
820 | this.setProperty(\font, font) | |
821 | } | |
822 | ||
823 | states_ { arg array; | |
824 | states = array; | |
825 | this.setProperty(\states, states); | |
826 | } | |
827 | ||
828 | properties { | |
829 | ^super.properties ++ #[\value, \font, \states] | |
830 | } | |
831 | ||
832 | defaultGetDrag { | |
833 | ^this.value | |
834 | } | |
835 | defaultCanReceiveDrag { | |
836 | ^currentDrag.isNumber or: { currentDrag.isKindOf(Function) }; | |
837 | } | |
838 | defaultReceiveDrag { | |
839 | if (currentDrag.isNumber) { | |
840 | this.valueAction = currentDrag; | |
841 | }{ | |
842 | this.action = currentDrag; | |
843 | }; | |
844 | } | |
845 | } | |
846 | ||
847 | SCStaticTextBase : SCView { | |
848 | var <string, <font, <object, <>setBoth=true; | |
849 | ||
850 | font_ { arg argFont; | |
851 | font = argFont; | |
852 | this.setProperty(\font, font) | |
853 | } | |
854 | ||
855 | string_ { arg argString; | |
856 | string = argString.asString; | |
857 | this.setProperty(\string, string) | |
858 | } | |
859 | align_ { arg align; | |
860 | this.setProperty(\align, align) | |
861 | } | |
862 | ||
863 | stringColor { | |
864 | ^this.getProperty(\stringColor, Color.new) | |
865 | } | |
866 | stringColor_ { arg color; | |
867 | this.setProperty(\stringColor, color) | |
868 | } | |
869 | ||
870 | object_ { arg obj; | |
871 | object = obj; | |
872 | if (setBoth) { this.string = object.asString(80); }; | |
873 | } | |
874 | ||
875 | properties { | |
876 | ^super.properties ++ #[\string, \font, \stringColor] | |
877 | } | |
878 | } | |
879 | ||
880 | SCStaticText : SCStaticTextBase { | |
881 | *paletteExample { arg parent, bounds; | |
882 | var v; | |
883 | v = this.new(parent, bounds); | |
884 | v.string = "The lazy brown fox"; | |
885 | ^v | |
886 | } | |
887 | } | |
888 | ||
889 | ||
890 | SCNumberBox : SCStaticTextBase { | |
891 | var <> keyString, <>step=1; | |
892 | var <>typingColor, <>normalColor; | |
893 | var <>clipLo = -inf, <>clipHi = inf, hit, inc=1.0, <>scroll=true, <>shift_step=0.1, <>ctrl_step=10; | |
894 | ||
895 | *paletteExample { arg parent, bounds; | |
896 | var v; | |
897 | v = this.new(parent, bounds); | |
898 | v.value = 123.456; | |
899 | ^v | |
900 | } | |
901 | ||
902 | init { arg argParent, argBounds; | |
903 | typingColor = Color.red; | |
904 | normalColor = Color.black; | |
905 | background = Color.white; | |
906 | parent = argParent.asView; // actual view | |
907 | this.prInit(parent.asView, argBounds.asRect,this.class.viewClass); | |
908 | argParent.add(this);//maybe window or viewadapter | |
909 | } | |
910 | ||
911 | increment { this.valueAction = this.value + step; } | |
912 | decrement { this.valueAction = this.value - step; } | |
913 | ||
914 | defaultKeyDownAction { arg char, modifiers, unicode; | |
915 | // standard chardown | |
916 | if (unicode == 16rF700, { this.increment; ^this }); | |
917 | if (unicode == 16rF703, { this.increment; ^this }); | |
918 | if (unicode == 16rF701, { this.decrement; ^this }); | |
919 | if (unicode == 16rF702, { this.decrement; ^this }); | |
920 | if ((char == 3.asAscii) || (char == $\r) || (char == $\n), { // enter key | |
921 | if (keyString.notNil,{ // no error on repeated enter | |
922 | this.valueAction_(keyString.asFloat); | |
923 | }); | |
924 | ^this | |
925 | }); | |
926 | if (char == 127.asAscii, { // delete key | |
927 | keyString = nil; | |
928 | this.string = object.asString; | |
929 | this.stringColor = normalColor; | |
930 | ^this | |
931 | }); | |
932 | if (char.isDecDigit || "+-.eE".includes(char), { | |
933 | if (keyString.isNil, { | |
934 | keyString = String.new; | |
935 | this.stringColor = typingColor; | |
936 | }); | |
937 | keyString = keyString.add(char); | |
938 | this.string = keyString; | |
939 | ^this | |
940 | }); | |
941 | ^nil // bubble if it's an invalid key | |
942 | } | |
943 | ||
944 | value { ^object } | |
945 | value_ { arg val; | |
946 | keyString = nil; | |
947 | this.stringColor = normalColor; | |
948 | object = val !? { val.clip(clipLo, clipHi) }; | |
949 | this.string = object.asString; | |
950 | } | |
951 | valueAction_ { arg val; | |
952 | var prev; | |
953 | prev = object; | |
954 | this.value = val !? { val.clip(clipLo, clipHi) }; | |
955 | if (object != prev, { this.doAction }); | |
956 | } | |
957 | ||
958 | boxColor { | |
959 | this.deprecated(thisMethod, SCView.findMethod(\background)); | |
960 | ^this.background; | |
961 | } | |
962 | boxColor_ { arg color; | |
963 | this.deprecated(thisMethod, SCView.findMethod(\background_)); | |
964 | this.background_(color) | |
965 | } | |
966 | ||
967 | properties { | |
968 | ^super.properties ++ #[\boxColor] | |
969 | } | |
970 | defaultGetDrag { | |
971 | ^object.asFloat | |
972 | } | |
973 | defaultCanReceiveDrag { | |
974 | ^currentDrag.isNumber; | |
975 | } | |
976 | defaultReceiveDrag { | |
977 | this.valueAction = currentDrag; | |
978 | } | |
979 | ||
980 | mouseDown { arg x, y, modifiers, buttonNumber, clickCount; | |
981 | hit = Point(x,y); | |
982 | if (scroll == true, { | |
983 | inc = 1.0; | |
984 | case | |
985 | { modifiers & 131072 == 131072 } // shift defaults to step x 0.1 | |
986 | { inc = shift_step } | |
987 | { modifiers & 262144 == 262144 } // control defaults to step x 10 | |
988 | { inc = ctrl_step }; | |
989 | }); | |
990 | mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount) | |
991 | } | |
992 | ||
993 | mouseMove { arg x, y, modifiers; | |
994 | var direction; | |
995 | if (scroll == true, { | |
996 | direction = 1.0; | |
997 | // horizontal or vertical scrolling: | |
998 | if ( (x - hit.x) < 0 or: { (y - hit.y) > 0 }) { direction = -1.0; }; | |
999 | ||
1000 | this.valueAction = (this.value + (inc * this.step * direction)); | |
1001 | hit = Point(x, y); | |
1002 | }); | |
1003 | mouseMoveAction.value(this, x, y, modifiers); | |
1004 | } | |
1005 | } |
0 | 0 | Main : Process { |
1 | 1 | // do not change the next lines manually: |
2 | 2 | //==== replace with new version from bash script ==== |
3 | classvar scVersionMajor=3, scVersionMinor=4, scVersionPostfix=""; | |
3 | classvar scVersionMajor=3, scVersionMinor=4, scVersionPostfix=".2"; | |
4 | 4 | //==== end replace ==== |
5 | 5 | |
6 | 6 | var <platform, argv; |
145 | 145 | container.wakeUpParentsToBundle(bundle); |
146 | 146 | this.sendObjectToBundle(bundle, container, extraArgs, index); |
147 | 147 | }; |
148 | nodeMap.wakeUpParentsToBundle(bundle); | |
148 | 149 | bundle.schedSend(server, clock ? TempoClock.default, quant); |
149 | 150 | } { |
150 | 151 | loaded = false; |
404 | 405 | var ctl, rate, numChannels, canBeMapped; |
405 | 406 | if(proxy.isNil) { ^this.unmap(key) }; |
406 | 407 | ctl = this.controlNames.detect { |x| x.name == key }; |
407 | rate = ctl.rate ?? { | |
408 | if(proxy.isNeutral) { | |
408 | rate = ctl.rate ?? { | |
409 | if(proxy.isNeutral) { | |
409 | 410 | if(this.isNeutral) { \audio } { this.rate } |
410 | } { | |
411 | proxy.rate | |
411 | } { | |
412 | proxy.rate | |
412 | 413 | } |
413 | 414 | }; |
414 | 415 | numChannels = ctl !? { ctl.defaultValue.asArray.size }; canBeMapped = proxy.initBus(rate, numChannels); |
418 | 419 | } { |
419 | 420 | "Could not link node proxies, no matching input found.".warn |
420 | 421 | }; |
421 | ^proxy; // returns first argument for further chaining | |
422 | ^proxy // returns first argument for further chaining | |
422 | 423 | } |
423 | 424 | |
424 | 425 | |
801 | 802 | if(loaded.not) { this.loadToBundle(bundle) }; |
802 | 803 | if(awake and: { this.isPlaying.not }) { |
803 | 804 | this.prepareToBundle(nil, bundle, \addToHead); |
804 | this.sendAllToBundle(bundle) | |
805 | this.sendAllToBundle(bundle); | |
805 | 806 | }; |
806 | 807 | }; |
807 | 808 | |
809 | 810 | |
810 | 811 | wakeUpParentsToBundle { | bundle, checkedAlready | |
811 | 812 | nodeMap.wakeUpParentsToBundle(bundle, checkedAlready); |
812 | objects.do{ arg item; item.wakeUpParentsToBundle(bundle, checkedAlready) }; | |
813 | objects.do { arg item; item.wakeUpParentsToBundle(bundle, checkedAlready) }; | |
813 | 814 | } |
814 | 815 | |
815 | 816 |
0 | + String | |
1 | { | |
2 | loadPath { arg warnIfNotFound=true; | |
3 | var obj,path; | |
4 | path = this.standardizePath; | |
5 | if(File.exists(path),{ | |
6 | { | |
7 | obj = thisProcess.interpreter.executeFile(path); | |
8 | //obj.didLoadFromPath(this); | |
9 | }.try({ arg err; | |
10 | ("In file: " + this).postln; | |
11 | err.throw; | |
12 | }); | |
13 | },{ | |
14 | if(warnIfNotFound,{ | |
15 | warn("String:loadPath file not found " + this + path); | |
16 | }); | |
17 | }); | |
18 | if(obj.isNil and: warnIfNotFound, { | |
19 | warn("String:loadPath found nil, empty contents or parse error in " + path); | |
20 | ||
21 | //^ObjectNotFound.new(path) | |
22 | }); | |
23 | ^obj | |
24 | } | |
25 | }⏎ |
29 | 29 | graphical = false |
30 | 30 | #the location of the rc file to source |
31 | 31 | rcloc = nil |
32 | ||
33 | # debian-based systems do not activate vim plugins automatically, we must check | |
34 | if %x[which vim-addons]!="" && %x[vim-addons -q status supercollider | grep installed]=="" | |
35 | puts "scvim has detected that you haven't activated the vim supercollider plugin." | |
36 | puts "to enable scvim to work, please execute either " | |
37 | puts " vim-addons install supercollider" | |
38 | puts "to enable it for the current user, or " | |
39 | puts " sudo vim-addons -w install supercollider" | |
40 | puts "to enable it system-wide." | |
41 | puts "" | |
42 | puts "Would you like me to run \"vim-addons install supercollider\" for you?" | |
43 | puts "Press 'y' and then Enter if so. Otherwise just press Enter to exit." | |
44 | userreply = gets.chomp | |
45 | if userreply == 'y' | |
46 | %x[vim-addons install supercollider] | |
47 | else | |
48 | exit | |
49 | end | |
50 | end | |
32 | 51 | |
33 | 52 | opts = OptionParser.new do |opts| |
34 | 53 | #the usage banner |
26 | 26 | if(scvim_cache_dir_env.isNil){ |
27 | 27 | scvim_cache_dir = "~/.scvim".standardizePath; |
28 | 28 | setenv("SCVIM_CACHE_DIR", scvim_cache_dir); |
29 | //inform("SCVim: I've set the cache dir based on the scvim dir"); | |
30 | 29 | }{ |
31 | 30 | scvim_cache_dir = scvim_cache_dir_env; |
32 | //inform("SCVim: I've set the cache dir based on the environment variable"); | |
33 | 31 | }; |
34 | 32 | StartUp.add{ |
35 | if(autoFirstRun and:{ File.exists(scvim_cache_dir).not }){ | |
36 | Task{ | |
37 | "SCVim: generating help docs, it will take a few moments. (This only happens the first time you launch scvim. See SCVim help file for more info.)".inform; | |
38 | this.updateCaches; | |
39 | this.updateHelpCache; | |
40 | "SCVim: finished generating help docs".inform; | |
41 | }.play; | |
33 | if(Platform.ideName=="scvim"){ | |
34 | if(autoFirstRun and:{ File.exists(scvim_cache_dir).not }){ | |
35 | Task{ | |
36 | "SCVim: generating help docs, it will take a few moments. (This only happens the first time you launch scvim. See SCVim help file for more info.)".inform; | |
37 | this.updateCaches; | |
38 | this.updateHelpCache; | |
39 | "SCVim: finished generating help docs".inform; | |
40 | }.play; | |
41 | }; | |
42 | 42 | }; |
43 | 43 | }; |
44 | 44 | } |