Commit 593e0a0eb65ac4498e30424b230366c3b286c9e9
1 parent
3ac09c86
ajout fichiers projet
Showing
228 changed files
with
14305 additions
and
0 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 228 files are displayed.
No preview for this file type
WiimoteWhiteboard/src/apple/dts/samplecode/osxadapter/OSXAdapter.java
0 → 100644
@@ -0,0 +1,152 @@ | @@ -0,0 +1,152 @@ | ||
1 | +package apple.dts.samplecode.osxadapter; | ||
2 | + | ||
3 | +import java.lang.reflect.InvocationHandler; | ||
4 | +import java.lang.reflect.InvocationTargetException; | ||
5 | +import java.lang.reflect.Method; | ||
6 | +import java.lang.reflect.Proxy; | ||
7 | + | ||
8 | + | ||
9 | +public class OSXAdapter implements InvocationHandler { | ||
10 | + | ||
11 | + protected Object targetObject; | ||
12 | + protected Method targetMethod; | ||
13 | + protected String proxySignature; | ||
14 | + | ||
15 | + static Object macOSXApplication; | ||
16 | + | ||
17 | + // Pass this method an Object and Method equipped to perform application shutdown logic | ||
18 | + // The method passed should return a boolean stating whether or not the quit should occur | ||
19 | + public static void setQuitHandler(Object target, Method quitHandler) { | ||
20 | + setHandler(new OSXAdapter("handleQuit", target, quitHandler)); | ||
21 | + } | ||
22 | + | ||
23 | + // Pass this method an Object and Method equipped to display application info | ||
24 | + // They will be called when the About menu item is selected from the application menu | ||
25 | + public static void setAboutHandler(Object target, Method aboutHandler) { | ||
26 | + boolean enableAboutMenu = (target != null && aboutHandler != null); | ||
27 | + if (enableAboutMenu) { | ||
28 | + setHandler(new OSXAdapter("handleAbout", target, aboutHandler)); | ||
29 | + } | ||
30 | + // If we're setting a handler, enable the About menu item by calling | ||
31 | + // com.apple.eawt.Application reflectively | ||
32 | + try { | ||
33 | + Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] { boolean.class }); | ||
34 | + enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enableAboutMenu) }); | ||
35 | + } catch (Exception ex) { | ||
36 | + System.err.println("OSXAdapter could not access the About Menu"); | ||
37 | + ex.printStackTrace(); | ||
38 | + } | ||
39 | + } | ||
40 | + | ||
41 | + // Pass this method an Object and a Method equipped to display application options | ||
42 | + // They will be called when the Preferences menu item is selected from the application menu | ||
43 | + public static void setPreferencesHandler(Object target, Method prefsHandler) { | ||
44 | + boolean enablePrefsMenu = (target != null && prefsHandler != null); | ||
45 | + if (enablePrefsMenu) { | ||
46 | + setHandler(new OSXAdapter("handlePreferences", target, prefsHandler)); | ||
47 | + } | ||
48 | + // If we're setting a handler, enable the Preferences menu item by calling | ||
49 | + // com.apple.eawt.Application reflectively | ||
50 | + try { | ||
51 | + Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class }); | ||
52 | + enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) }); | ||
53 | + } catch (Exception ex) { | ||
54 | + System.err.println("OSXAdapter could not access the About Menu"); | ||
55 | + ex.printStackTrace(); | ||
56 | + } | ||
57 | + } | ||
58 | + | ||
59 | + // Pass this method an Object and a Method equipped to handle document events from the Finder | ||
60 | + // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the | ||
61 | + // application bundle's Info.plist | ||
62 | + public static void setFileHandler(Object target, Method fileHandler) { | ||
63 | + setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) { | ||
64 | + // Override OSXAdapter.callTarget to send information on the | ||
65 | + // file to be opened | ||
66 | + @Override | ||
67 | + public boolean callTarget(Object appleEvent) { | ||
68 | + if (appleEvent != null) { | ||
69 | + try { | ||
70 | + Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null); | ||
71 | + String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[])null); | ||
72 | + this.targetMethod.invoke(this.targetObject, new Object[] { filename }); | ||
73 | + } catch (Exception ex) { | ||
74 | + | ||
75 | + } | ||
76 | + } | ||
77 | + return true; | ||
78 | + } | ||
79 | + }); | ||
80 | + } | ||
81 | + | ||
82 | + // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener | ||
83 | + public static void setHandler(OSXAdapter adapter) { | ||
84 | + try { | ||
85 | + Class<?> applicationClass = Class.forName("com.apple.eawt.Application"); | ||
86 | + if (macOSXApplication == null) { | ||
87 | + macOSXApplication = applicationClass.getConstructor((Class[])null).newInstance((Object[])null); | ||
88 | + } | ||
89 | + Class<?> applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener"); | ||
90 | + Method addListenerMethod = applicationClass.getDeclaredMethod("addApplicationListener", new Class[] { applicationListenerClass }); | ||
91 | + // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener | ||
92 | + Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] { applicationListenerClass }, adapter); | ||
93 | + addListenerMethod.invoke(macOSXApplication, new Object[] { osxAdapterProxy }); | ||
94 | + } catch (ClassNotFoundException cnfe) { | ||
95 | + System.err.println("This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + cnfe + ")"); | ||
96 | + } catch (Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods | ||
97 | + System.err.println("Mac OS X Adapter could not talk to EAWT:"); | ||
98 | + ex.printStackTrace(); | ||
99 | + } | ||
100 | + } | ||
101 | + | ||
102 | + // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example), | ||
103 | + // the Object that will ultimately perform the task, and the Method to be called on that Object | ||
104 | + protected OSXAdapter(String proxySignature, Object target, Method handler) { | ||
105 | + this.proxySignature = proxySignature; | ||
106 | + this.targetObject = target; | ||
107 | + this.targetMethod = handler; | ||
108 | + } | ||
109 | + | ||
110 | + // Override this method to perform any operations on the event | ||
111 | + // that comes with the various callbacks | ||
112 | + // See setFileHandler above for an example | ||
113 | + public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException { | ||
114 | + Object result = targetMethod.invoke(targetObject, (Object[])null); | ||
115 | + if (result == null) { | ||
116 | + return true; | ||
117 | + } | ||
118 | + return Boolean.valueOf(result.toString()).booleanValue(); | ||
119 | + } | ||
120 | + | ||
121 | + // InvocationHandler implementation | ||
122 | + // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked | ||
123 | + public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { | ||
124 | + if (isCorrectMethod(method, args)) { | ||
125 | + boolean handled = callTarget(args[0]); | ||
126 | + setApplicationEventHandled(args[0], handled); | ||
127 | + } | ||
128 | + // All of the ApplicationListener methods are void; return null regardless of what happens | ||
129 | + return null; | ||
130 | + } | ||
131 | + | ||
132 | + // Compare the method that was called to the intended method when the OSXAdapter instance was created | ||
133 | + // (e.g. handleAbout, handleQuit, handleOpenFile, etc.) | ||
134 | + protected boolean isCorrectMethod(Method method, Object[] args) { | ||
135 | + return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1); | ||
136 | + } | ||
137 | + | ||
138 | + // It is important to mark the ApplicationEvent as handled and cancel the default behavior | ||
139 | + // This method checks for a boolean result from the proxy method and sets the event accordingly | ||
140 | + protected void setApplicationEventHandled(Object event, boolean handled) { | ||
141 | + if (event != null) { | ||
142 | + try { | ||
143 | + Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class }); | ||
144 | + // If the target method returns a boolean, use that as a hint | ||
145 | + setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) }); | ||
146 | + } catch (Exception ex) { | ||
147 | + System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event); | ||
148 | + ex.printStackTrace(); | ||
149 | + } | ||
150 | + } | ||
151 | + } | ||
152 | +} |
WiimoteWhiteboard/src/apple/dts/samplecode/osxadapter/OSXAdapter.java~
0 → 100644
@@ -0,0 +1,152 @@ | @@ -0,0 +1,152 @@ | ||
1 | +package apple.dts.samplecode.osxadapter; | ||
2 | + | ||
3 | +import java.lang.reflect.InvocationHandler; | ||
4 | +import java.lang.reflect.InvocationTargetException; | ||
5 | +import java.lang.reflect.Method; | ||
6 | +import java.lang.reflect.Proxy; | ||
7 | + | ||
8 | + | ||
9 | +public class OSXAdapter implements InvocationHandler { | ||
10 | + | ||
11 | + protected Object targetObject; | ||
12 | + protected Method targetMethod; | ||
13 | + protected String proxySignature; | ||
14 | + | ||
15 | + static Object macOSXApplication; | ||
16 | + | ||
17 | + // Pass this method an Object and Method equipped to perform application shutdown logic | ||
18 | + // The method passed should return a boolean stating whether or not the quit should occur | ||
19 | + public static void setQuitHandler(Object target, Method quitHandler) { | ||
20 | + setHandler(new OSXAdapter("handleQuit", target, quitHandler)); | ||
21 | + } | ||
22 | + | ||
23 | + // Pass this method an Object and Method equipped to display application info | ||
24 | + // They will be called when the About menu item is selected from the application menu | ||
25 | + public static void setAboutHandler(Object target, Method aboutHandler) { | ||
26 | + boolean enableAboutMenu = (target != null && aboutHandler != null); | ||
27 | + if (enableAboutMenu) { | ||
28 | + setHandler(new OSXAdapter("handleAbout", target, aboutHandler)); | ||
29 | + } | ||
30 | + // If we're setting a handler, enable the About menu item by calling | ||
31 | + // com.apple.eawt.Application reflectively | ||
32 | + try { | ||
33 | + Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] { boolean.class }); | ||
34 | + enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enableAboutMenu) }); | ||
35 | + } catch (Exception ex) { | ||
36 | + System.err.println("OSXAdapter could not access the About Menu"); | ||
37 | + ex.printStackTrace(); | ||
38 | + } | ||
39 | + } | ||
40 | + | ||
41 | + // Pass this method an Object and a Method equipped to display application options | ||
42 | + // They will be called when the Preferences menu item is selected from the application menu | ||
43 | + public static void setPreferencesHandler(Object target, Method prefsHandler) { | ||
44 | + boolean enablePrefsMenu = (target != null && prefsHandler != null); | ||
45 | + if (enablePrefsMenu) { | ||
46 | + setHandler(new OSXAdapter("handlePreferences", target, prefsHandler)); | ||
47 | + } | ||
48 | + // If we're setting a handler, enable the Preferences menu item by calling | ||
49 | + // com.apple.eawt.Application reflectively | ||
50 | + try { | ||
51 | + Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class }); | ||
52 | + enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) }); | ||
53 | + } catch (Exception ex) { | ||
54 | + System.err.println("OSXAdapter could not access the About Menu"); | ||
55 | + ex.printStackTrace(); | ||
56 | + } | ||
57 | + } | ||
58 | + | ||
59 | + // Pass this method an Object and a Method equipped to handle document events from the Finder | ||
60 | + // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the | ||
61 | + // application bundle's Info.plist | ||
62 | + public static void setFileHandler(Object target, Method fileHandler) { | ||
63 | + setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) { | ||
64 | + // Override OSXAdapter.callTarget to send information on the | ||
65 | + // file to be opened | ||
66 | + @Override | ||
67 | + public boolean callTarget(Object appleEvent) { | ||
68 | + if (appleEvent != null) { | ||
69 | + try { | ||
70 | + Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null); | ||
71 | + String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[])null); | ||
72 | + this.targetMethod.invoke(this.targetObject, new Object[] { filename }); | ||
73 | + } catch (Exception ex) { | ||
74 | + | ||
75 | + } | ||
76 | + } | ||
77 | + return true; | ||
78 | + } | ||
79 | + }); | ||
80 | + } | ||
81 | + | ||
82 | + // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener | ||
83 | + public static void setHandler(OSXAdapter adapter) { | ||
84 | + try { | ||
85 | + Class<?> applicationClass = Class.forName("com.apple.eawt.Application"); | ||
86 | + if (macOSXApplication == null) { | ||
87 | + macOSXApplication = applicationClass.getConstructor((Class[])null).newInstance((Object[])null); | ||
88 | + } | ||
89 | + Class<?> applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener"); | ||
90 | + Method addListenerMethod = applicationClass.getDeclaredMethod("addApplicationListener", new Class[] { applicationListenerClass }); | ||
91 | + // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener | ||
92 | + Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] { applicationListenerClass }, adapter); | ||
93 | + addListenerMethod.invoke(macOSXApplication, new Object[] { osxAdapterProxy }); | ||
94 | + } catch (ClassNotFoundException cnfe) { | ||
95 | + System.err.println("This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + cnfe + ")"); | ||
96 | + } catch (Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods | ||
97 | + System.err.println("Mac OS X Adapter could not talk to EAWT:"); | ||
98 | + ex.printStackTrace(); | ||
99 | + } | ||
100 | + } | ||
101 | + | ||
102 | + // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example), | ||
103 | + // the Object that will ultimately perform the task, and the Method to be called on that Object | ||
104 | + protected OSXAdapter(String proxySignature, Object target, Method handler) { | ||
105 | + this.proxySignature = proxySignature; | ||
106 | + this.targetObject = target; | ||
107 | + this.targetMethod = handler; | ||
108 | + } | ||
109 | + | ||
110 | + // Override this method to perform any operations on the event | ||
111 | + // that comes with the various callbacks | ||
112 | + // See setFileHandler above for an example | ||
113 | + public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException { | ||
114 | + Object result = targetMethod.invoke(targetObject, (Object[])null); | ||
115 | + if (result == null) { | ||
116 | + return true; | ||
117 | + } | ||
118 | + return Boolean.valueOf(result.toString()).booleanValue(); | ||
119 | + } | ||
120 | + | ||
121 | + // InvocationHandler implementation | ||
122 | + // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked | ||
123 | + public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { | ||
124 | + if (isCorrectMethod(method, args)) { | ||
125 | + boolean handled = callTarget(args[0]); | ||
126 | + setApplicationEventHandled(args[0], handled); | ||
127 | + } | ||
128 | + // All of the ApplicationListener methods are void; return null regardless of what happens | ||
129 | + return null; | ||
130 | + } | ||
131 | + | ||
132 | + // Compare the method that was called to the intended method when the OSXAdapter instance was created | ||
133 | + // (e.g. handleAbout, handleQuit, handleOpenFile, etc.) | ||
134 | + protected boolean isCorrectMethod(Method method, Object[] args) { | ||
135 | + return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1); | ||
136 | + } | ||
137 | + | ||
138 | + // It is important to mark the ApplicationEvent as handled and cancel the default behavior | ||
139 | + // This method checks for a boolean result from the proxy method and sets the event accordingly | ||
140 | + protected void setApplicationEventHandled(Object event, boolean handled) { | ||
141 | + if (event != null) { | ||
142 | + try { | ||
143 | + Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class }); | ||
144 | + // If the target method returns a boolean, use that as a hint | ||
145 | + setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) }); | ||
146 | + } catch (Exception ex) { | ||
147 | + System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event); | ||
148 | + ex.printStackTrace(); | ||
149 | + } | ||
150 | + } | ||
151 | + } | ||
152 | +} |
WiimoteWhiteboard/src/javax/media/jai/PerspectiveTransform.java
0 → 100644
@@ -0,0 +1,1095 @@ | @@ -0,0 +1,1095 @@ | ||
1 | +package javax.media.jai; | ||
2 | +import java.awt.geom.AffineTransform; | ||
3 | +import java.awt.geom.Point2D; | ||
4 | +import java.awt.geom.NoninvertibleTransformException; | ||
5 | +import java.io.Serializable; | ||
6 | + | ||
7 | +public final class PerspectiveTransform implements Cloneable, Serializable { | ||
8 | + | ||
9 | + private static final double PERSPECTIVE_DIVIDE_EPSILON = 1.0e-10; | ||
10 | + | ||
11 | + double m00, m01, m02, m10, m11, m12, m20, m21, m22; | ||
12 | + | ||
13 | + /** Constructs an identity PerspectiveTransform. */ | ||
14 | + public PerspectiveTransform() { | ||
15 | + m00 = m11 = m22 = 1.0; | ||
16 | + m01 = m02 = m10 = m12 = m20 = m21 = 0.0; | ||
17 | + } | ||
18 | + | ||
19 | + /** | ||
20 | + * Constructs a new PerspectiveTransform from 9 floats. | ||
21 | + */ | ||
22 | + public PerspectiveTransform(float m00, float m01, float m02, | ||
23 | + float m10, float m11, float m12, | ||
24 | + float m20, float m21, float m22) { | ||
25 | + this.m00 = m00; | ||
26 | + this.m01 = m01; | ||
27 | + this.m02 = m02; | ||
28 | + this.m10 = m10; | ||
29 | + this.m11 = m11; | ||
30 | + this.m12 = m12; | ||
31 | + this.m20 = m20; | ||
32 | + this.m21 = m21; | ||
33 | + this.m22 = m22; | ||
34 | + } | ||
35 | + | ||
36 | + /** | ||
37 | + * Constructs a new PerspectiveTransform from 9 doubles. | ||
38 | + */ | ||
39 | + public PerspectiveTransform(double m00, double m01, double m02, | ||
40 | + double m10, double m11, double m12, | ||
41 | + double m20, double m21, double m22) { | ||
42 | + this.m00 = m00; | ||
43 | + this.m01 = m01; | ||
44 | + this.m02 = m02; | ||
45 | + this.m10 = m10; | ||
46 | + this.m11 = m11; | ||
47 | + this.m12 = m12; | ||
48 | + this.m20 = m20; | ||
49 | + this.m21 = m21; | ||
50 | + this.m22 = m22; | ||
51 | + } | ||
52 | + | ||
53 | + public PerspectiveTransform(float[] flatmatrix) { | ||
54 | + if ( flatmatrix == null ) { | ||
55 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
56 | + } | ||
57 | + | ||
58 | + m00 = flatmatrix[0]; | ||
59 | + m01 = flatmatrix[1]; | ||
60 | + m02 = flatmatrix[2]; | ||
61 | + m10 = flatmatrix[3]; | ||
62 | + m11 = flatmatrix[4]; | ||
63 | + m12 = flatmatrix[5]; | ||
64 | + m20 = flatmatrix[6]; | ||
65 | + m21 = flatmatrix[7]; | ||
66 | + m22 = flatmatrix[8]; | ||
67 | + } | ||
68 | + | ||
69 | + public PerspectiveTransform(float[][] matrix) { | ||
70 | + if ( matrix == null ) { | ||
71 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
72 | + } | ||
73 | + | ||
74 | + m00 = matrix[0][0]; | ||
75 | + m01 = matrix[0][1]; | ||
76 | + m02 = matrix[0][2]; | ||
77 | + m10 = matrix[1][0]; | ||
78 | + m11 = matrix[1][1]; | ||
79 | + m12 = matrix[1][2]; | ||
80 | + m20 = matrix[2][0]; | ||
81 | + m21 = matrix[2][1]; | ||
82 | + m22 = matrix[2][2]; | ||
83 | + } | ||
84 | + | ||
85 | + public PerspectiveTransform(double[] flatmatrix) { | ||
86 | + if ( flatmatrix == null ) { | ||
87 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
88 | + } | ||
89 | + | ||
90 | + m00 = flatmatrix[0]; | ||
91 | + m01 = flatmatrix[1]; | ||
92 | + m02 = flatmatrix[2]; | ||
93 | + m10 = flatmatrix[3]; | ||
94 | + m11 = flatmatrix[4]; | ||
95 | + m12 = flatmatrix[5]; | ||
96 | + m20 = flatmatrix[6]; | ||
97 | + m21 = flatmatrix[7]; | ||
98 | + m22 = flatmatrix[8]; | ||
99 | + } | ||
100 | + | ||
101 | + /** | ||
102 | + * Constructs a new PerspectiveTransform from a two-dimensional | ||
103 | + * array of doubles. | ||
104 | + */ | ||
105 | + public PerspectiveTransform(double[][] matrix) { | ||
106 | + if ( matrix == null ) { | ||
107 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
108 | + } | ||
109 | + | ||
110 | + m00 = matrix[0][0]; | ||
111 | + m01 = matrix[0][1]; | ||
112 | + m02 = matrix[0][2]; | ||
113 | + m10 = matrix[1][0]; | ||
114 | + m11 = matrix[1][1]; | ||
115 | + m12 = matrix[1][2]; | ||
116 | + m20 = matrix[2][0]; | ||
117 | + m21 = matrix[2][1]; | ||
118 | + m22 = matrix[2][2]; | ||
119 | + } | ||
120 | + | ||
121 | + /** | ||
122 | + * Constructs a new PerspectiveTransform with the same effect | ||
123 | + * as an existing AffineTransform. | ||
124 | + * @throws IllegalArgumentException if transform is null | ||
125 | + */ | ||
126 | + public PerspectiveTransform(AffineTransform transform) { | ||
127 | + if ( transform == null ) { | ||
128 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
129 | + } | ||
130 | + | ||
131 | + m00 = transform.getScaleX(); | ||
132 | + m01 = transform.getShearX(); | ||
133 | + m02 = transform.getTranslateX(); | ||
134 | + m10 = transform.getShearY(); | ||
135 | + m11 = transform.getScaleY(); | ||
136 | + m12 = transform.getTranslateY(); | ||
137 | + m20 = 0.0; | ||
138 | + m21 = 0.0; | ||
139 | + m22 = 1.0; | ||
140 | + } | ||
141 | + | ||
142 | + /** | ||
143 | + * Replaces the matrix with its adjoint. | ||
144 | + */ | ||
145 | + private final void makeAdjoint() { | ||
146 | + double m00p = m11*m22 - m12*m21; | ||
147 | + double m01p = m12*m20 - m10*m22; | ||
148 | + double m02p = m10*m21 - m11*m20; | ||
149 | + double m10p = m02*m21 - m01*m22; | ||
150 | + double m11p = m00*m22 - m02*m20; | ||
151 | + double m12p = m01*m20 - m00*m21; | ||
152 | + double m20p = m01*m12 - m02*m11; | ||
153 | + double m21p = m02*m10 - m00*m12; | ||
154 | + double m22p = m00*m11 - m01*m10; | ||
155 | + | ||
156 | + m00 = m00p; | ||
157 | + m01 = m10p; | ||
158 | + m02 = m20p; | ||
159 | + m10 = m01p; | ||
160 | + m11 = m11p; | ||
161 | + m12 = m21p; | ||
162 | + m20 = m02p; | ||
163 | + m21 = m12p; | ||
164 | + m22 = m22p; | ||
165 | + } | ||
166 | + | ||
167 | + private final void normalize() { | ||
168 | + double invscale = 1.0/m22; | ||
169 | + m00 *= invscale; | ||
170 | + m01 *= invscale; | ||
171 | + m02 *= invscale; | ||
172 | + m10 *= invscale; | ||
173 | + m11 *= invscale; | ||
174 | + m12 *= invscale; | ||
175 | + m20 *= invscale; | ||
176 | + m21 *= invscale; | ||
177 | + m22 = 1.0; | ||
178 | + } | ||
179 | + | ||
180 | + private static final void getSquareToQuad(double x0, double y0, | ||
181 | + double x1, double y1, | ||
182 | + double x2, double y2, | ||
183 | + double x3, double y3, | ||
184 | + PerspectiveTransform tx) { | ||
185 | + double dx3 = x0 - x1 + x2 - x3; | ||
186 | + double dy3 = y0 - y1 + y2 - y3; | ||
187 | + | ||
188 | + tx.m22 = 1.0F; | ||
189 | + | ||
190 | + if ((dx3 == 0.0F) && (dy3 == 0.0F)) { | ||
191 | + tx.m00 = x1 - x0; | ||
192 | + tx.m01 = x2 - x1; | ||
193 | + tx.m02 = x0; | ||
194 | + tx.m10 = y1 - y0; | ||
195 | + tx.m11 = y2 - y1; | ||
196 | + tx.m12 = y0; | ||
197 | + tx.m20 = 0.0F; | ||
198 | + tx.m21 = 0.0F; | ||
199 | + } else { | ||
200 | + double dx1 = x1 - x2; | ||
201 | + double dy1 = y1 - y2; | ||
202 | + double dx2 = x3 - x2; | ||
203 | + double dy2 = y3 - y2; | ||
204 | + | ||
205 | + double invdet = 1.0F/(dx1*dy2 - dx2*dy1); | ||
206 | + tx.m20 = (dx3*dy2 - dx2*dy3)*invdet; | ||
207 | + tx.m21 = (dx1*dy3 - dx3*dy1)*invdet; | ||
208 | + tx.m00 = x1 - x0 + tx.m20*x1; | ||
209 | + tx.m01 = x3 - x0 + tx.m21*x3; | ||
210 | + tx.m02 = x0; | ||
211 | + tx.m10 = y1 - y0 + tx.m20*y1; | ||
212 | + tx.m11 = y3 - y0 + tx.m21*y3; | ||
213 | + tx.m12 = y0; | ||
214 | + } | ||
215 | + } | ||
216 | + | ||
217 | + public static PerspectiveTransform getSquareToQuad(double x0, double y0, | ||
218 | + double x1, double y1, | ||
219 | + double x2, double y2, | ||
220 | + double x3, double y3) { | ||
221 | + PerspectiveTransform tx = new PerspectiveTransform(); | ||
222 | + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx); | ||
223 | + return tx; | ||
224 | + } | ||
225 | + | ||
226 | + | ||
227 | + public static PerspectiveTransform getSquareToQuad(float x0, float y0, | ||
228 | + float x1, float y1, | ||
229 | + float x2, float y2, | ||
230 | + float x3, float y3) { | ||
231 | + return getSquareToQuad((double)x0, (double)y0, | ||
232 | + (double)x1, (double)y1, | ||
233 | + (double)x2, (double)y2, | ||
234 | + (double)x3, (double)y3); | ||
235 | + } | ||
236 | + | ||
237 | + | ||
238 | + /** | ||
239 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
240 | + * quadrilateral onto the unit square. | ||
241 | + */ | ||
242 | + public static PerspectiveTransform getQuadToSquare(double x0, double y0, | ||
243 | + double x1, double y1, | ||
244 | + double x2, double y2, | ||
245 | + double x3, double y3) { | ||
246 | + PerspectiveTransform tx = new PerspectiveTransform(); | ||
247 | + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx); | ||
248 | + tx.makeAdjoint(); | ||
249 | + return tx; | ||
250 | + } | ||
251 | + | ||
252 | + /** | ||
253 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
254 | + * quadrilateral onto the unit square. | ||
255 | + */ | ||
256 | + public static PerspectiveTransform getQuadToSquare(float x0, float y0, | ||
257 | + float x1, float y1, | ||
258 | + float x2, float y2, | ||
259 | + float x3, float y3) { | ||
260 | + return getQuadToSquare((double)x0, (double)y0, | ||
261 | + (double)x1, (double)y1, | ||
262 | + (double)x2, (double)y2, | ||
263 | + (double)x3, (double)y3); | ||
264 | + } | ||
265 | + | ||
266 | + /** | ||
267 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
268 | + * quadrilateral onto another arbitrary quadrilateral. | ||
269 | + */ | ||
270 | + public static PerspectiveTransform getQuadToQuad(double x0, double y0, | ||
271 | + double x1, double y1, | ||
272 | + double x2, double y2, | ||
273 | + double x3, double y3, | ||
274 | + double x0p, double y0p, | ||
275 | + double x1p, double y1p, | ||
276 | + double x2p, double y2p, | ||
277 | + double x3p, double y3p) { | ||
278 | + PerspectiveTransform tx1 = | ||
279 | + getQuadToSquare(x0, y0, x1, y1, x2, y2, x3, y3); | ||
280 | + | ||
281 | + PerspectiveTransform tx2 = | ||
282 | + getSquareToQuad(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); | ||
283 | + | ||
284 | + tx1.concatenate(tx2); | ||
285 | + return tx1; | ||
286 | + } | ||
287 | + | ||
288 | + | ||
289 | + /** | ||
290 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
291 | + * quadrilateral onto another arbitrary quadrilateral. | ||
292 | + */ | ||
293 | + public static PerspectiveTransform getQuadToQuad(float x0, float y0, | ||
294 | + float x1, float y1, | ||
295 | + float x2, float y2, | ||
296 | + float x3, float y3, | ||
297 | + float x0p, float y0p, | ||
298 | + float x1p, float y1p, | ||
299 | + float x2p, float y2p, | ||
300 | + float x3p, float y3p) { | ||
301 | + return getQuadToQuad((double)x0, (double)y0, | ||
302 | + (double)x1, (double)y1, | ||
303 | + (double)x2, (double)y2, | ||
304 | + (double)x3, (double)y3, | ||
305 | + (double)x0p, (double)y0p, | ||
306 | + (double)x1p, (double)y1p, | ||
307 | + (double)x2p, (double)y2p, | ||
308 | + (double)x3p, (double)y3p); | ||
309 | + } | ||
310 | + | ||
311 | + /** | ||
312 | + * Returns the determinant of the matrix representation of the | ||
313 | + * transform. | ||
314 | + */ | ||
315 | + public double getDeterminant() { | ||
316 | + return ( (m00 * ((m11 * m22) - (m12 * m21))) - | ||
317 | + (m01 * ((m10 * m22) - (m12 * m20))) + | ||
318 | + (m02 * ((m10 * m21) - (m11 * m20))) ); | ||
319 | + | ||
320 | + } | ||
321 | + | ||
322 | + /** | ||
323 | + * Retrieves the 9 specifiable values in the 3x3 affine | ||
324 | + * transformation matrix into an array of double precision values. | ||
325 | + * The values are stored into the array as | ||
326 | + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }. | ||
327 | + */ | ||
328 | + public double[] getMatrix(double[] flatmatrix) { | ||
329 | + if (flatmatrix == null) { | ||
330 | + flatmatrix = new double[9]; | ||
331 | + } | ||
332 | + | ||
333 | + flatmatrix[0] = m00; | ||
334 | + flatmatrix[1] = m01; | ||
335 | + flatmatrix[2] = m02; | ||
336 | + flatmatrix[3] = m10; | ||
337 | + flatmatrix[4] = m11; | ||
338 | + flatmatrix[5] = m12; | ||
339 | + flatmatrix[6] = m20; | ||
340 | + flatmatrix[7] = m21; | ||
341 | + flatmatrix[8] = m22; | ||
342 | + | ||
343 | + return flatmatrix; | ||
344 | + } | ||
345 | + | ||
346 | + /** | ||
347 | + * Retrieves the 9 specifiable values in the 3x3 affine | ||
348 | + * transformation matrix into a 2-dimensional array of double | ||
349 | + * precision values. The values are stored into the 2-dimensional | ||
350 | + * array using the row index as the first subscript and the column | ||
351 | + * index as the second. | ||
352 | + * | ||
353 | + */ | ||
354 | + public double[][] getMatrix(double[][] matrix) { | ||
355 | + if (matrix == null) { | ||
356 | + matrix = new double[3][3]; | ||
357 | + } | ||
358 | + | ||
359 | + matrix[0][0] = m00; | ||
360 | + matrix[0][1] = m01; | ||
361 | + matrix[0][2] = m02; | ||
362 | + matrix[1][0] = m10; | ||
363 | + matrix[1][1] = m11; | ||
364 | + matrix[1][2] = m12; | ||
365 | + matrix[2][0] = m20; | ||
366 | + matrix[2][1] = m21; | ||
367 | + matrix[2][2] = m22; | ||
368 | + | ||
369 | + return matrix; | ||
370 | + } | ||
371 | + | ||
372 | + /** | ||
373 | + * Concatenates this transform with a translation transformation. | ||
374 | + */ | ||
375 | + public void translate(double tx, double ty) { | ||
376 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
377 | + Tx.setToTranslation(tx, ty); | ||
378 | + concatenate(Tx); | ||
379 | + } | ||
380 | + | ||
381 | + /** | ||
382 | + * Concatenates this transform with a rotation transformation. | ||
383 | + */ | ||
384 | + public void rotate(double theta) { | ||
385 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
386 | + Tx.setToRotation(theta); | ||
387 | + concatenate(Tx); | ||
388 | + } | ||
389 | + | ||
390 | + /** | ||
391 | + * Concatenates this transform with a translated rotation transformation. | ||
392 | + */ | ||
393 | + public void rotate(double theta, double x, double y) { | ||
394 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
395 | + Tx.setToRotation(theta, x, y); | ||
396 | + concatenate(Tx); | ||
397 | + } | ||
398 | + | ||
399 | + /** | ||
400 | + * Concatenates this transform with a scaling transformation. | ||
401 | + */ | ||
402 | + public void scale(double sx, double sy) { | ||
403 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
404 | + Tx.setToScale(sx, sy); | ||
405 | + concatenate(Tx); | ||
406 | + } | ||
407 | + | ||
408 | + /** | ||
409 | + * Concatenates this transform with a shearing transformation. | ||
410 | + */ | ||
411 | + public void shear(double shx, double shy) { | ||
412 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
413 | + Tx.setToShear(shx, shy); | ||
414 | + concatenate(Tx); | ||
415 | + } | ||
416 | + | ||
417 | + /** | ||
418 | + * Resets this transform to the Identity transform. | ||
419 | + */ | ||
420 | + public void setToIdentity() { | ||
421 | + m00 = m11 = m22 = 1.0; | ||
422 | + m01 = m10 = m02 = m20 = m12 = m21 = 0.0; | ||
423 | + } | ||
424 | + | ||
425 | + /** | ||
426 | + * Sets this transform to a translation transformation. | ||
427 | + */ | ||
428 | + public void setToTranslation(double tx, double ty) { | ||
429 | + m00 = 1.0; | ||
430 | + m01 = 0.0; | ||
431 | + m02 = tx; | ||
432 | + m10 = 0.0; | ||
433 | + m11 = 1.0; | ||
434 | + m12 = ty; | ||
435 | + m20 = 0.0; | ||
436 | + m21 = 0.0; | ||
437 | + m22 = 1.0; | ||
438 | + } | ||
439 | + | ||
440 | + /** | ||
441 | + * Sets this transform to a rotation transformation. | ||
442 | + */ | ||
443 | + public void setToRotation(double theta) { | ||
444 | + m00 = Math.cos(theta); | ||
445 | + m01 = -Math.sin(theta); | ||
446 | + m02 = 0.0; | ||
447 | + m10 = - m01; | ||
448 | + m11 = m00; | ||
449 | + m12 = 0.0; | ||
450 | + m20 = 0.0; | ||
451 | + m21 = 0.0; | ||
452 | + m22 = 1.0; | ||
453 | + } | ||
454 | + | ||
455 | + public void setToRotation(double theta, double x, double y) { | ||
456 | + setToRotation(theta); | ||
457 | + double sin = m10; | ||
458 | + double oneMinusCos = 1.0 - m00; | ||
459 | + m02 = x * oneMinusCos + y * sin; | ||
460 | + m12 = y * oneMinusCos - x * sin; | ||
461 | + } | ||
462 | + | ||
463 | + public void setToScale(double sx, double sy) { | ||
464 | + m00 = sx; | ||
465 | + m01 = 0.0; | ||
466 | + m02 = 0.0; | ||
467 | + m10 = 0.0; | ||
468 | + m11 = sy; | ||
469 | + m12 = 0.0; | ||
470 | + m20 = 0.0; | ||
471 | + m21 = 0.0; | ||
472 | + m22 = 1.0; | ||
473 | + } | ||
474 | + | ||
475 | + /** | ||
476 | + * Sets this transform to a shearing transformation | ||
477 | + * with shear factors sx and sy. | ||
478 | + */ | ||
479 | + public void setToShear(double shx, double shy) { | ||
480 | + m00 = 1.0; | ||
481 | + m01 = shx; | ||
482 | + m02 = 0.0; | ||
483 | + m10 = shy; | ||
484 | + m11 = 1.0; | ||
485 | + m12 = 0.0; | ||
486 | + m20 = 0.0; | ||
487 | + m21 = 0.0; | ||
488 | + m22 = 1.0; | ||
489 | + } | ||
490 | + | ||
491 | + /** | ||
492 | + * Sets this transform to a given AffineTransform. | ||
493 | + * @throws IllegalArgumentException if Tx is null | ||
494 | + */ | ||
495 | + public void setTransform(AffineTransform Tx) { | ||
496 | + if ( Tx == null ) { | ||
497 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
498 | + } | ||
499 | + | ||
500 | + m00 = Tx.getScaleX(); | ||
501 | + m01 = Tx.getShearX(); | ||
502 | + m02 = Tx.getTranslateX(); | ||
503 | + m10 = Tx.getShearY(); | ||
504 | + m11 = Tx.getScaleY(); | ||
505 | + m12 = Tx.getTranslateY(); | ||
506 | + m20 = 0.0; | ||
507 | + m21 = 0.0; | ||
508 | + m22 = 1.0; | ||
509 | + } | ||
510 | + | ||
511 | + /** | ||
512 | + * Sets this transform to a given PerspectiveTransform. | ||
513 | + * @throws IllegalArgumentException if Tx is null | ||
514 | + */ | ||
515 | + public void setTransform(PerspectiveTransform Tx) { | ||
516 | + if ( Tx == null ) { | ||
517 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
518 | + } | ||
519 | + | ||
520 | + m00 = Tx.m00; | ||
521 | + m01 = Tx.m01; | ||
522 | + m02 = Tx.m02; | ||
523 | + m10 = Tx.m10; | ||
524 | + m11 = Tx.m11; | ||
525 | + m12 = Tx.m12; | ||
526 | + m20 = Tx.m20; | ||
527 | + m21 = Tx.m21; | ||
528 | + m22 = Tx.m22; | ||
529 | + } | ||
530 | + | ||
531 | + public void setTransform(float m00, float m10, float m20, | ||
532 | + float m01, float m11, float m21, | ||
533 | + float m02, float m12, float m22) { | ||
534 | + this.m00 = (double)m00; | ||
535 | + this.m01 = (double)m01; | ||
536 | + this.m02 = (double)m02; | ||
537 | + this.m10 = (double)m10; | ||
538 | + this.m11 = (double)m11; | ||
539 | + this.m12 = (double)m12; | ||
540 | + this.m20 = (double)m20; | ||
541 | + this.m21 = (double)m21; | ||
542 | + this.m22 = (double)m22; | ||
543 | + } | ||
544 | + | ||
545 | + public void setTransform(double[][] matrix) { | ||
546 | + if ( matrix == null ) { | ||
547 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
548 | + } | ||
549 | + | ||
550 | + m00 = matrix[0][0]; | ||
551 | + m01 = matrix[0][1]; | ||
552 | + m02 = matrix[0][2]; | ||
553 | + m10 = matrix[1][0]; | ||
554 | + m11 = matrix[1][1]; | ||
555 | + m12 = matrix[1][2]; | ||
556 | + m20 = matrix[2][0]; | ||
557 | + m21 = matrix[2][1]; | ||
558 | + m22 = matrix[2][2]; | ||
559 | + } | ||
560 | + | ||
561 | + /** | ||
562 | + * Post-concatenates a given AffineTransform to this transform. | ||
563 | + * @throws IllegalArgumentException if Tx is null | ||
564 | + */ | ||
565 | + public void concatenate(AffineTransform Tx) { | ||
566 | + if ( Tx == null ) { | ||
567 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
568 | + } | ||
569 | + | ||
570 | + double tx_m00 = Tx.getScaleX(); | ||
571 | + double tx_m01 = Tx.getShearX(); | ||
572 | + double tx_m02 = Tx.getTranslateX(); | ||
573 | + double tx_m10 = Tx.getShearY(); | ||
574 | + double tx_m11 = Tx.getScaleY(); | ||
575 | + double tx_m12 = Tx.getTranslateY(); | ||
576 | + | ||
577 | + double m00p = m00*tx_m00 + m10*tx_m01 + m20*tx_m02; | ||
578 | + double m01p = m01*tx_m00 + m11*tx_m01 + m21*tx_m02; | ||
579 | + double m02p = m02*tx_m00 + m12*tx_m01 + m22*tx_m02; | ||
580 | + double m10p = m00*tx_m10 + m10*tx_m11 + m20*tx_m12; | ||
581 | + double m11p = m01*tx_m10 + m11*tx_m11 + m21*tx_m12; | ||
582 | + double m12p = m02*tx_m10 + m12*tx_m11 + m22*tx_m12; | ||
583 | + double m20p = m20; | ||
584 | + double m21p = m21; | ||
585 | + double m22p = m22; | ||
586 | + | ||
587 | + m00 = m00p; | ||
588 | + m10 = m10p; | ||
589 | + m20 = m20p; | ||
590 | + m01 = m01p; | ||
591 | + m11 = m11p; | ||
592 | + m21 = m21p; | ||
593 | + m02 = m02p; | ||
594 | + m12 = m12p; | ||
595 | + m22 = m22p; | ||
596 | + } | ||
597 | + | ||
598 | + /** | ||
599 | + * Post-concatenates a given PerspectiveTransform to this transform. | ||
600 | + * @throws IllegalArgumentException if Tx is null | ||
601 | + */ | ||
602 | + public void concatenate(PerspectiveTransform Tx) { | ||
603 | + if ( Tx == null ) { | ||
604 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
605 | + } | ||
606 | + | ||
607 | + double m00p = m00*Tx.m00 + m10*Tx.m01 + m20*Tx.m02; | ||
608 | + double m10p = m00*Tx.m10 + m10*Tx.m11 + m20*Tx.m12; | ||
609 | + double m20p = m00*Tx.m20 + m10*Tx.m21 + m20*Tx.m22; | ||
610 | + double m01p = m01*Tx.m00 + m11*Tx.m01 + m21*Tx.m02; | ||
611 | + double m11p = m01*Tx.m10 + m11*Tx.m11 + m21*Tx.m12; | ||
612 | + double m21p = m01*Tx.m20 + m11*Tx.m21 + m21*Tx.m22; | ||
613 | + double m02p = m02*Tx.m00 + m12*Tx.m01 + m22*Tx.m02; | ||
614 | + double m12p = m02*Tx.m10 + m12*Tx.m11 + m22*Tx.m12; | ||
615 | + double m22p = m02*Tx.m20 + m12*Tx.m21 + m22*Tx.m22; | ||
616 | + | ||
617 | + m00 = m00p; | ||
618 | + m10 = m10p; | ||
619 | + m20 = m20p; | ||
620 | + m01 = m01p; | ||
621 | + m11 = m11p; | ||
622 | + m21 = m21p; | ||
623 | + m02 = m02p; | ||
624 | + m12 = m12p; | ||
625 | + m22 = m22p; | ||
626 | + } | ||
627 | + | ||
628 | + /** | ||
629 | + * Pre-concatenates a given AffineTransform to this transform. | ||
630 | + * @throws IllegalArgumentException if Tx is null | ||
631 | + */ | ||
632 | + public void preConcatenate(AffineTransform Tx) { | ||
633 | + if ( Tx == null ) { | ||
634 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
635 | + } | ||
636 | + | ||
637 | + // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1 | ||
638 | + | ||
639 | + double tx_m00 = Tx.getScaleX(); | ||
640 | + double tx_m01 = Tx.getShearX(); | ||
641 | + double tx_m02 = Tx.getTranslateX(); | ||
642 | + double tx_m10 = Tx.getShearY(); | ||
643 | + double tx_m11 = Tx.getScaleY(); | ||
644 | + double tx_m12 = Tx.getTranslateY(); | ||
645 | + | ||
646 | + double m00p = tx_m00*m00 + tx_m10*m01; | ||
647 | + double m01p = tx_m01*m00 + tx_m11*m01; | ||
648 | + double m02p = tx_m02*m00 + tx_m12*m01 + m02; | ||
649 | + double m10p = tx_m00*m10 + tx_m10*m11; | ||
650 | + double m11p = tx_m01*m10 + tx_m11*m11; | ||
651 | + double m12p = tx_m02*m10 + tx_m12*m11 + m12; | ||
652 | + double m20p = tx_m00*m20 + tx_m10*m21; | ||
653 | + double m21p = tx_m01*m20 + tx_m11*m21; | ||
654 | + double m22p = tx_m02*m20 + tx_m12*m21 + m22; | ||
655 | + | ||
656 | + m00 = m00p; | ||
657 | + m10 = m10p; | ||
658 | + m20 = m20p; | ||
659 | + m01 = m01p; | ||
660 | + m11 = m11p; | ||
661 | + m21 = m21p; | ||
662 | + m02 = m02p; | ||
663 | + m12 = m12p; | ||
664 | + m22 = m22p; | ||
665 | + } | ||
666 | + | ||
667 | + /** | ||
668 | + * Pre-concatenates a given PerspectiveTransform to this transform. | ||
669 | + * @throws IllegalArgumentException if Tx is null | ||
670 | + */ | ||
671 | + public void preConcatenate(PerspectiveTransform Tx) { | ||
672 | + if ( Tx == null ) { | ||
673 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
674 | + } | ||
675 | + | ||
676 | + double m00p = Tx.m00*m00 + Tx.m10*m01 + Tx.m20*m02; | ||
677 | + double m10p = Tx.m00*m10 + Tx.m10*m11 + Tx.m20*m12; | ||
678 | + double m20p = Tx.m00*m20 + Tx.m10*m21 + Tx.m20*m22; | ||
679 | + double m01p = Tx.m01*m00 + Tx.m11*m01 + Tx.m21*m02; | ||
680 | + double m11p = Tx.m01*m10 + Tx.m11*m11 + Tx.m21*m12; | ||
681 | + double m21p = Tx.m01*m20 + Tx.m11*m21 + Tx.m21*m22; | ||
682 | + double m02p = Tx.m02*m00 + Tx.m12*m01 + Tx.m22*m02; | ||
683 | + double m12p = Tx.m02*m10 + Tx.m12*m11 + Tx.m22*m12; | ||
684 | + double m22p = Tx.m02*m20 + Tx.m12*m21 + Tx.m22*m22; | ||
685 | + | ||
686 | + m00 = m00p; | ||
687 | + m10 = m10p; | ||
688 | + m20 = m20p; | ||
689 | + m01 = m01p; | ||
690 | + m11 = m11p; | ||
691 | + m21 = m21p; | ||
692 | + m02 = m02p; | ||
693 | + m12 = m12p; | ||
694 | + m22 = m22p; | ||
695 | + } | ||
696 | + | ||
697 | + /** | ||
698 | + * Returns a new PerpectiveTransform that is the inverse | ||
699 | + * of the current transform. | ||
700 | + * @throws NoninvertibleTransformException if transform cannot be inverted | ||
701 | + */ | ||
702 | + public PerspectiveTransform createInverse() | ||
703 | + throws NoninvertibleTransformException, CloneNotSupportedException { | ||
704 | + | ||
705 | + PerspectiveTransform tx = (PerspectiveTransform)clone(); | ||
706 | + tx.makeAdjoint(); | ||
707 | + if (Math.abs(tx.m22) < PERSPECTIVE_DIVIDE_EPSILON) { | ||
708 | + throw new NoninvertibleTransformException(JaiI18N.getString("PerspectiveTransform0")); | ||
709 | + } | ||
710 | + tx.normalize(); | ||
711 | + return tx; | ||
712 | + } | ||
713 | + | ||
714 | + /** | ||
715 | + * Returns a new PerpectiveTransform that is the adjoint, | ||
716 | + * of the current transform. The adjoint is defined as | ||
717 | + * the matrix of cofactors, which in turn are the determinants | ||
718 | + * of the submatrices defined by removing the row and column | ||
719 | + * of each element from the original matrix in turn. | ||
720 | + */ | ||
721 | + public PerspectiveTransform createAdjoint() | ||
722 | + throws CloneNotSupportedException{ | ||
723 | + | ||
724 | + PerspectiveTransform tx = (PerspectiveTransform)clone(); | ||
725 | + tx.makeAdjoint(); | ||
726 | + return tx; | ||
727 | + } | ||
728 | + | ||
729 | + /** | ||
730 | + * Transforms the specified ptSrc and stores the result in ptDst. | ||
731 | + * If ptDst is null, a new Point2D object will be allocated before | ||
732 | + * storing. In either case, ptDst containing the transformed point | ||
733 | + * is returned for convenience. | ||
734 | + * Note that ptSrc and ptDst can the same. In this case, the input | ||
735 | + * point will be overwritten with the transformed point. | ||
736 | + * @throws IllegalArgumentException if ptSrc is null | ||
737 | + */ | ||
738 | + public Point2D transform(Point2D ptSrc, Point2D ptDst) { | ||
739 | + if ( ptSrc == null ) { | ||
740 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
741 | + } | ||
742 | + | ||
743 | + if (ptDst == null) { | ||
744 | + if (ptSrc instanceof Point2D.Double) { | ||
745 | + ptDst = new Point2D.Double(); | ||
746 | + } else { | ||
747 | + ptDst = new Point2D.Float(); | ||
748 | + } | ||
749 | + } | ||
750 | + | ||
751 | + double x = ptSrc.getX(); | ||
752 | + double y = ptSrc.getY(); | ||
753 | + double w = m20 * x + m21 * y + m22; | ||
754 | + ptDst.setLocation((m00 * x + m01 * y + m02) / w, | ||
755 | + (m10 * x + m11 * y + m12) / w); | ||
756 | + | ||
757 | + return ptDst; | ||
758 | + } | ||
759 | + | ||
760 | + /** | ||
761 | + * Transforms an array of point objects by this transform. | ||
762 | + * @throws IllegalArgumentException if ptSrc is null | ||
763 | + * @throws IllegalArgumentException if ptDst is null | ||
764 | + * @throws ArrayIndexOutOfBoundsException if ptSrc is too small | ||
765 | + */ | ||
766 | + public void transform(Point2D[] ptSrc, int srcOff, | ||
767 | + Point2D[] ptDst, int dstOff, | ||
768 | + int numPts) { | ||
769 | + | ||
770 | + if ( ptSrc == null || ptDst == null ) { | ||
771 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
772 | + } | ||
773 | + | ||
774 | + while (numPts-- > 0) { | ||
775 | + Point2D src = ptSrc[srcOff++]; | ||
776 | + Point2D dst = ptDst[dstOff++]; | ||
777 | + if (dst == null) { | ||
778 | + if (src instanceof Point2D.Double) { | ||
779 | + dst = new Point2D.Double(); | ||
780 | + } else { | ||
781 | + dst = new Point2D.Float(); | ||
782 | + } | ||
783 | + ptDst[dstOff - 1] = dst; | ||
784 | + } | ||
785 | + | ||
786 | + double x = src.getX(); | ||
787 | + double y = src.getY(); | ||
788 | + double w = m20 * x + m21 * y + m22; | ||
789 | + | ||
790 | + if (w == 0) { | ||
791 | + dst.setLocation(x, y); | ||
792 | + } else { | ||
793 | + dst.setLocation((m00 * x + m01 * y + m02) / w, | ||
794 | + (m10 * x + m11 * y + m12) / w); | ||
795 | + } | ||
796 | + } | ||
797 | + } | ||
798 | + | ||
799 | + /** | ||
800 | + * Transforms an array of floating point coordinates by this transform. | ||
801 | + * @throws IllegalArgumentException if srcPts is null | ||
802 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
803 | + */ | ||
804 | + public void transform(float[] srcPts, int srcOff, | ||
805 | + float[] dstPts, int dstOff, | ||
806 | + int numPts) { | ||
807 | + | ||
808 | + if ( srcPts == null ) { | ||
809 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
810 | + } | ||
811 | + | ||
812 | + if (dstPts == null) { | ||
813 | + dstPts = new float[numPts * 2 + dstOff]; | ||
814 | + } | ||
815 | + | ||
816 | + while (numPts-- > 0) { | ||
817 | + float x = srcPts[srcOff++]; | ||
818 | + float y = srcPts[srcOff++]; | ||
819 | + double w = m20 * x + m21 * y + m22; | ||
820 | + | ||
821 | + if (w == 0) { | ||
822 | + dstPts[dstOff++] = x; | ||
823 | + dstPts[dstOff++] = y; | ||
824 | + } else { | ||
825 | + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w); | ||
826 | + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w); | ||
827 | + } | ||
828 | + } | ||
829 | + } | ||
830 | + | ||
831 | + /** | ||
832 | + * Transforms an array of double precision coordinates by this transform. | ||
833 | + * @throws IllegalArgumentException if srcPts is null | ||
834 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
835 | + */ | ||
836 | + public void transform(double[] srcPts, int srcOff, | ||
837 | + double[] dstPts, int dstOff, | ||
838 | + int numPts) { | ||
839 | + | ||
840 | + if ( srcPts == null ) { | ||
841 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
842 | + } | ||
843 | + | ||
844 | + if (dstPts == null) { | ||
845 | + dstPts = new double[numPts * 2 + dstOff]; | ||
846 | + } | ||
847 | + | ||
848 | + while (numPts-- > 0) { | ||
849 | + double x = srcPts[srcOff++]; | ||
850 | + double y = srcPts[srcOff++]; | ||
851 | + double w = m20 * x + m21 * y + m22; | ||
852 | + | ||
853 | + if (w == 0) { | ||
854 | + dstPts[dstOff++] = x; | ||
855 | + dstPts[dstOff++] = y; | ||
856 | + } else { | ||
857 | + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w; | ||
858 | + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w; | ||
859 | + } | ||
860 | + } | ||
861 | + } | ||
862 | + | ||
863 | + /** | ||
864 | + * Transforms an array of floating point coordinates by this transform, | ||
865 | + * storing the results into an array of doubles. | ||
866 | + * @throws IllegalArgumentException if srcPts is null | ||
867 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
868 | + */ | ||
869 | + public void transform(float[] srcPts, int srcOff, | ||
870 | + double[] dstPts, int dstOff, | ||
871 | + int numPts) { | ||
872 | + | ||
873 | + if ( srcPts == null ) { | ||
874 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
875 | + } | ||
876 | + | ||
877 | + if (dstPts == null) { | ||
878 | + dstPts = new double[numPts * 2 + dstOff]; | ||
879 | + } | ||
880 | + | ||
881 | + while (numPts-- > 0) { | ||
882 | + float x = srcPts[srcOff++]; | ||
883 | + float y = srcPts[srcOff++]; | ||
884 | + double w = m20 * x + m21 * y + m22; | ||
885 | + | ||
886 | + if (w == 0) { | ||
887 | + dstPts[dstOff++] = x; | ||
888 | + dstPts[dstOff++] = y; | ||
889 | + } else { | ||
890 | + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w; | ||
891 | + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w; | ||
892 | + } | ||
893 | + } | ||
894 | + } | ||
895 | + | ||
896 | + /** | ||
897 | + * Transforms an array of double precision coordinates by this transform, | ||
898 | + * storing the results into an array of floats. | ||
899 | + * @throws IllegalArgumentException if srcPts is null | ||
900 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
901 | + */ | ||
902 | + public void transform(double[] srcPts, int srcOff, | ||
903 | + float[] dstPts, int dstOff, | ||
904 | + int numPts) { | ||
905 | + | ||
906 | + if ( srcPts == null ) { | ||
907 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
908 | + } | ||
909 | + | ||
910 | + if (dstPts == null) { | ||
911 | + dstPts = new float[numPts * 2 + dstOff]; | ||
912 | + } | ||
913 | + | ||
914 | + while (numPts-- > 0) { | ||
915 | + double x = srcPts[srcOff++]; | ||
916 | + double y = srcPts[srcOff++]; | ||
917 | + double w = m20 * x + m21 * y + m22; | ||
918 | + | ||
919 | + if (w == 0) { | ||
920 | + dstPts[dstOff++] = (float)x; | ||
921 | + dstPts[dstOff++] = (float)y; | ||
922 | + } else { | ||
923 | + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w); | ||
924 | + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w); | ||
925 | + } | ||
926 | + } | ||
927 | + } | ||
928 | + | ||
929 | + /** | ||
930 | + * Inverse transforms the specified ptSrc and stores the result in ptDst. | ||
931 | + * If ptDst is null, a new Point2D object will be allocated before | ||
932 | + * storing. In either case, ptDst containing the transformed point | ||
933 | + * is returned for convenience. | ||
934 | + | ||
935 | + * @throws NoninvertibleTransformException if the matrix cannot be inverted. | ||
936 | + * @throws IllegalArgumentException if ptSrc is null | ||
937 | + */ | ||
938 | + public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) | ||
939 | + throws NoninvertibleTransformException | ||
940 | + { | ||
941 | + if ( ptSrc == null ) { | ||
942 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
943 | + } | ||
944 | + | ||
945 | + if (ptDst == null) { | ||
946 | + if (ptSrc instanceof Point2D.Double) { | ||
947 | + ptDst = new Point2D.Double(); | ||
948 | + } else { | ||
949 | + ptDst = new Point2D.Float(); | ||
950 | + } | ||
951 | + } | ||
952 | + // Copy source coords into local variables in case src == dst | ||
953 | + double x = ptSrc.getX(); | ||
954 | + double y = ptSrc.getY(); | ||
955 | + | ||
956 | + double tmp_x = (m11*m22 - m12*m21) * x + | ||
957 | + (m02*m21 - m01*m22) * y + | ||
958 | + (m01*m12 - m02*m11); | ||
959 | + double tmp_y = (m12*m20 - m10*m22) * x + | ||
960 | + (m00*m22 - m02*m20) * y + | ||
961 | + (m02*m10 - m00*m12); | ||
962 | + double w = (m10*m21 - m11*m20) * x + | ||
963 | + (m01*m20 - m00*m21) * y + | ||
964 | + (m00*m11 - m01*m10); | ||
965 | + | ||
966 | + double wabs = w; | ||
967 | + if (w < 0) { | ||
968 | + wabs = - w; | ||
969 | + } | ||
970 | + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) { | ||
971 | + throw new | ||
972 | + NoninvertibleTransformException( | ||
973 | + JaiI18N.getString("PerspectiveTransform1")); | ||
974 | + } | ||
975 | + | ||
976 | + ptDst.setLocation(tmp_x/w, tmp_y/w); | ||
977 | + | ||
978 | + return ptDst; | ||
979 | + } | ||
980 | + | ||
981 | + /** | ||
982 | + * Inverse transforms an array of double precision coordinates by | ||
983 | + * this transform. | ||
984 | + * @throws NoninvertibleTransformException if the matrix cannot be inverted. | ||
985 | + * @throws IllegalArgumentException if srcPts is null | ||
986 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
987 | + * @throws NoninvertibleTransformException transform cannot be inverted | ||
988 | + */ | ||
989 | + public void inverseTransform(double[] srcPts, int srcOff, | ||
990 | + double[] dstPts, int dstOff, | ||
991 | + int numPts) | ||
992 | + throws NoninvertibleTransformException | ||
993 | + { | ||
994 | + if ( srcPts == null ) { | ||
995 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
996 | + } | ||
997 | + | ||
998 | + if (dstPts == null) { | ||
999 | + dstPts = new double[numPts * 2 + dstOff]; | ||
1000 | + } | ||
1001 | + | ||
1002 | + while (numPts-- > 0) { | ||
1003 | + double x = srcPts[srcOff++]; | ||
1004 | + double y = srcPts[srcOff++]; | ||
1005 | + | ||
1006 | + double tmp_x = (m11*m22 - m12*m21) * x + | ||
1007 | + (m02*m21 - m01*m22) * y + | ||
1008 | + (m01*m12 - m02*m11); | ||
1009 | + double tmp_y = (m12*m20 - m10*m22) * x + | ||
1010 | + (m00*m22 - m02*m20) * y + | ||
1011 | + (m02*m10 - m00*m12); | ||
1012 | + double w = (m10*m21 - m11*m20) * x + | ||
1013 | + (m01*m20 - m00*m21) * y + | ||
1014 | + (m00*m11 - m01*m10); | ||
1015 | + | ||
1016 | + double wabs = w; | ||
1017 | + if (w < 0) { | ||
1018 | + wabs = - w; | ||
1019 | + } | ||
1020 | + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) { | ||
1021 | + throw new NoninvertibleTransformException( | ||
1022 | + JaiI18N.getString("PerspectiveTransform1")); | ||
1023 | + } | ||
1024 | + | ||
1025 | + dstPts[dstOff++] = tmp_x / w; | ||
1026 | + dstPts[dstOff++] = tmp_y / w; | ||
1027 | + } | ||
1028 | + } | ||
1029 | + | ||
1030 | + /** | ||
1031 | + * Returns a String that represents the value of this Object. | ||
1032 | + */ | ||
1033 | + public String toString() { | ||
1034 | + StringBuffer sb = new StringBuffer(); | ||
1035 | + sb.append("Perspective transform matrix\n"); | ||
1036 | + sb.append(this.m00); | ||
1037 | + sb.append("\t"); | ||
1038 | + sb.append(this.m01); | ||
1039 | + sb.append("\t"); | ||
1040 | + sb.append(this.m02); | ||
1041 | + sb.append("\n"); | ||
1042 | + sb.append(this.m10); | ||
1043 | + sb.append("\t"); | ||
1044 | + sb.append(this.m11); | ||
1045 | + sb.append("\t"); | ||
1046 | + sb.append(this.m12); | ||
1047 | + sb.append("\n"); | ||
1048 | + sb.append(this.m20); | ||
1049 | + sb.append("\t"); | ||
1050 | + sb.append(this.m21); | ||
1051 | + sb.append("\t"); | ||
1052 | + sb.append(this.m22); | ||
1053 | + sb.append("\n"); | ||
1054 | + return new String(sb); | ||
1055 | + } | ||
1056 | + | ||
1057 | + /** | ||
1058 | + * Returns the boolean true value if this PerspectiveTransform is an | ||
1059 | + * identity transform. Returns false otherwise. | ||
1060 | + */ | ||
1061 | + public boolean isIdentity() { | ||
1062 | + return m01 == 0.0 && m02 == 0.0 && | ||
1063 | + m10 == 0.0 && m12 == 0.0 && | ||
1064 | + m20 == 0.0 && m21 == 0.0 && | ||
1065 | + m22 != 0.0 && m00/m22 == 1.0 && m11/m22 == 1.0; | ||
1066 | + } | ||
1067 | + | ||
1068 | + /** | ||
1069 | + * Returns a copy of this PerspectiveTransform object. | ||
1070 | + */ | ||
1071 | + public Object clone() { | ||
1072 | + try { | ||
1073 | + return super.clone(); | ||
1074 | + } catch (CloneNotSupportedException e) { | ||
1075 | + // this shouldn't happen, since we are Cloneable | ||
1076 | + throw new InternalError(); | ||
1077 | + } | ||
1078 | + } | ||
1079 | + | ||
1080 | + | ||
1081 | + /** | ||
1082 | + * Tests if this PerspectiveTransform equals a supplied one. | ||
1083 | + */ | ||
1084 | + public boolean equals(Object obj) { | ||
1085 | + if (!(obj instanceof PerspectiveTransform)) { | ||
1086 | + return false; | ||
1087 | + } | ||
1088 | + | ||
1089 | + PerspectiveTransform a = (PerspectiveTransform)obj; | ||
1090 | + | ||
1091 | + return ((m00 == a.m00) && (m10 == a.m10) && (m20 == a.m20) && | ||
1092 | + (m01 == a.m01) && (m11 == a.m11) && (m21 == a.m21) && | ||
1093 | + (m02 == a.m02) && (m12 == a.m12) && (m22 == a.m22)); | ||
1094 | + } | ||
1095 | +} |
WiimoteWhiteboard/src/javax/media/jai/PerspectiveTransform.java~
0 → 100644
@@ -0,0 +1,1439 @@ | @@ -0,0 +1,1439 @@ | ||
1 | +/* | ||
2 | + * $RCSfile: PerspectiveTransform.java,v $ | ||
3 | + * | ||
4 | + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. | ||
5 | + * | ||
6 | + * Use is subject to license terms. | ||
7 | + * | ||
8 | + * $Revision: 1.1 $ | ||
9 | + * $Date: 2005/02/11 04:57:15 $ | ||
10 | + * $State: Exp $ | ||
11 | + */ | ||
12 | +package javax.media.jai; | ||
13 | +import java.awt.geom.AffineTransform; | ||
14 | +import java.awt.geom.Point2D; | ||
15 | +import java.awt.geom.NoninvertibleTransformException; | ||
16 | +import java.io.Serializable; | ||
17 | + | ||
18 | + | ||
19 | +/** | ||
20 | + * A 2D perspective (or projective) transform, used by various OpImages. | ||
21 | + * | ||
22 | + * <p> A perspective transformation is capable of mapping an arbitrary | ||
23 | + * quadrilateral into another arbitrary quadrilateral, while | ||
24 | + * preserving the straightness of lines. Unlike an affine | ||
25 | + * transformation, the parallelism of lines in the source is not | ||
26 | + * necessarily preserved in the output. | ||
27 | + * | ||
28 | + * <p> Such a coordinate transformation can be represented by a 3x3 | ||
29 | + * matrix which transforms homogenous source coordinates | ||
30 | + * <code>(x, y, 1)</code> into destination coordinates | ||
31 | + * <code>(x', y', w)</code>. To convert back into non-homogenous | ||
32 | + * coordinates (X, Y), <code>x'</code> and <code>y'</code> are divided by | ||
33 | + * <code>w</code>. | ||
34 | + * | ||
35 | + * <pre> | ||
36 | + * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ] | ||
37 | + * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ] | ||
38 | + * [ w ] [ m20 m21 m22 ] [ 1 ] [ m20x + m21y + m22 ] | ||
39 | + * | ||
40 | + * x' = (m00x + m01y + m02) | ||
41 | + * y' = (m10x + m11y + m12) | ||
42 | + * | ||
43 | + * w = (m20x + m21y + m22) | ||
44 | + * | ||
45 | + * X = x' / w | ||
46 | + * Y = y' / w | ||
47 | + * </pre> | ||
48 | + */ | ||
49 | +public final class PerspectiveTransform implements Cloneable, Serializable { | ||
50 | + | ||
51 | + private static final double PERSPECTIVE_DIVIDE_EPSILON = 1.0e-10; | ||
52 | + | ||
53 | + /** An element of the transform matrix. */ | ||
54 | + double m00, m01, m02, m10, m11, m12, m20, m21, m22; | ||
55 | + | ||
56 | + /** Constructs an identity PerspectiveTransform. */ | ||
57 | + public PerspectiveTransform() { | ||
58 | + m00 = m11 = m22 = 1.0; | ||
59 | + m01 = m02 = m10 = m12 = m20 = m21 = 0.0; | ||
60 | + } | ||
61 | + | ||
62 | + /** | ||
63 | + * Constructs a new PerspectiveTransform from 9 floats. | ||
64 | + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. | ||
65 | + */ | ||
66 | + public PerspectiveTransform(float m00, float m01, float m02, | ||
67 | + float m10, float m11, float m12, | ||
68 | + float m20, float m21, float m22) { | ||
69 | + this.m00 = m00; | ||
70 | + this.m01 = m01; | ||
71 | + this.m02 = m02; | ||
72 | + this.m10 = m10; | ||
73 | + this.m11 = m11; | ||
74 | + this.m12 = m12; | ||
75 | + this.m20 = m20; | ||
76 | + this.m21 = m21; | ||
77 | + this.m22 = m22; | ||
78 | + } | ||
79 | + | ||
80 | + /** | ||
81 | + * Constructs a new PerspectiveTransform from 9 doubles. | ||
82 | + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. | ||
83 | + */ | ||
84 | + public PerspectiveTransform(double m00, double m01, double m02, | ||
85 | + double m10, double m11, double m12, | ||
86 | + double m20, double m21, double m22) { | ||
87 | + this.m00 = m00; | ||
88 | + this.m01 = m01; | ||
89 | + this.m02 = m02; | ||
90 | + this.m10 = m10; | ||
91 | + this.m11 = m11; | ||
92 | + this.m12 = m12; | ||
93 | + this.m20 = m20; | ||
94 | + this.m21 = m21; | ||
95 | + this.m22 = m22; | ||
96 | + } | ||
97 | + | ||
98 | + /** | ||
99 | + * Constructs a new PerspectiveTransform from a one-dimensional | ||
100 | + * array of 9 floats, in row-major order. | ||
101 | + * The values in the array are assumed to be | ||
102 | + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }. | ||
103 | + * @throws IllegalArgumentException if flatmatrix is null | ||
104 | + * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small | ||
105 | + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. | ||
106 | + */ | ||
107 | + public PerspectiveTransform(float[] flatmatrix) { | ||
108 | + if ( flatmatrix == null ) { | ||
109 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
110 | + } | ||
111 | + | ||
112 | + m00 = flatmatrix[0]; | ||
113 | + m01 = flatmatrix[1]; | ||
114 | + m02 = flatmatrix[2]; | ||
115 | + m10 = flatmatrix[3]; | ||
116 | + m11 = flatmatrix[4]; | ||
117 | + m12 = flatmatrix[5]; | ||
118 | + m20 = flatmatrix[6]; | ||
119 | + m21 = flatmatrix[7]; | ||
120 | + m22 = flatmatrix[8]; | ||
121 | + } | ||
122 | + | ||
123 | + /** | ||
124 | + * Constructs a new PerspectiveTransform from a two-dimensional | ||
125 | + * array of floats. | ||
126 | + * @throws IllegalArgumentException if matrix is null | ||
127 | + * @throws ArrayIndexOutOfBoundsException if matrix is too small | ||
128 | + * | ||
129 | + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. | ||
130 | + */ | ||
131 | + public PerspectiveTransform(float[][] matrix) { | ||
132 | + if ( matrix == null ) { | ||
133 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
134 | + } | ||
135 | + | ||
136 | + m00 = matrix[0][0]; | ||
137 | + m01 = matrix[0][1]; | ||
138 | + m02 = matrix[0][2]; | ||
139 | + m10 = matrix[1][0]; | ||
140 | + m11 = matrix[1][1]; | ||
141 | + m12 = matrix[1][2]; | ||
142 | + m20 = matrix[2][0]; | ||
143 | + m21 = matrix[2][1]; | ||
144 | + m22 = matrix[2][2]; | ||
145 | + } | ||
146 | + | ||
147 | + /** | ||
148 | + * Constructs a new PerspectiveTransform from a one-dimensional | ||
149 | + * array of 9 doubles, in row-major order. | ||
150 | + * The values in the array are assumed to be | ||
151 | + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }. | ||
152 | + * @throws IllegalArgumentException if flatmatrix is null | ||
153 | + * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small | ||
154 | + * | ||
155 | + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. | ||
156 | + */ | ||
157 | + public PerspectiveTransform(double[] flatmatrix) { | ||
158 | + if ( flatmatrix == null ) { | ||
159 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
160 | + } | ||
161 | + | ||
162 | + m00 = flatmatrix[0]; | ||
163 | + m01 = flatmatrix[1]; | ||
164 | + m02 = flatmatrix[2]; | ||
165 | + m10 = flatmatrix[3]; | ||
166 | + m11 = flatmatrix[4]; | ||
167 | + m12 = flatmatrix[5]; | ||
168 | + m20 = flatmatrix[6]; | ||
169 | + m21 = flatmatrix[7]; | ||
170 | + m22 = flatmatrix[8]; | ||
171 | + } | ||
172 | + | ||
173 | + /** | ||
174 | + * Constructs a new PerspectiveTransform from a two-dimensional | ||
175 | + * array of doubles. | ||
176 | + * @throws IllegalArgumentException if matrix is null | ||
177 | + * @throws ArrayIndexOutOfBoundsException if matrix is too small | ||
178 | + */ | ||
179 | + public PerspectiveTransform(double[][] matrix) { | ||
180 | + if ( matrix == null ) { | ||
181 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
182 | + } | ||
183 | + | ||
184 | + m00 = matrix[0][0]; | ||
185 | + m01 = matrix[0][1]; | ||
186 | + m02 = matrix[0][2]; | ||
187 | + m10 = matrix[1][0]; | ||
188 | + m11 = matrix[1][1]; | ||
189 | + m12 = matrix[1][2]; | ||
190 | + m20 = matrix[2][0]; | ||
191 | + m21 = matrix[2][1]; | ||
192 | + m22 = matrix[2][2]; | ||
193 | + } | ||
194 | + | ||
195 | + /** | ||
196 | + * Constructs a new PerspectiveTransform with the same effect | ||
197 | + * as an existing AffineTransform. | ||
198 | + * @throws IllegalArgumentException if transform is null | ||
199 | + */ | ||
200 | + public PerspectiveTransform(AffineTransform transform) { | ||
201 | + if ( transform == null ) { | ||
202 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
203 | + } | ||
204 | + | ||
205 | + m00 = transform.getScaleX(); | ||
206 | + m01 = transform.getShearX(); | ||
207 | + m02 = transform.getTranslateX(); | ||
208 | + m10 = transform.getShearY(); | ||
209 | + m11 = transform.getScaleY(); | ||
210 | + m12 = transform.getTranslateY(); | ||
211 | + m20 = 0.0; | ||
212 | + m21 = 0.0; | ||
213 | + m22 = 1.0; | ||
214 | + } | ||
215 | + | ||
216 | + /** | ||
217 | + * Replaces the matrix with its adjoint. | ||
218 | + */ | ||
219 | + private final void makeAdjoint() { | ||
220 | + double m00p = m11*m22 - m12*m21; | ||
221 | + double m01p = m12*m20 - m10*m22; // flipped sign | ||
222 | + double m02p = m10*m21 - m11*m20; | ||
223 | + double m10p = m02*m21 - m01*m22; // flipped sign | ||
224 | + double m11p = m00*m22 - m02*m20; | ||
225 | + double m12p = m01*m20 - m00*m21; // flipped sign | ||
226 | + double m20p = m01*m12 - m02*m11; | ||
227 | + double m21p = m02*m10 - m00*m12; // flipped sign | ||
228 | + double m22p = m00*m11 - m01*m10; | ||
229 | + | ||
230 | + // Transpose and copy sub-determinants | ||
231 | + m00 = m00p; | ||
232 | + m01 = m10p; | ||
233 | + m02 = m20p; | ||
234 | + m10 = m01p; | ||
235 | + m11 = m11p; | ||
236 | + m12 = m21p; | ||
237 | + m20 = m02p; | ||
238 | + m21 = m12p; | ||
239 | + m22 = m22p; | ||
240 | + } | ||
241 | + | ||
242 | + /** | ||
243 | + * Scales the matrix elements so m22 is equal to 1.0. | ||
244 | + * m22 must not be equal to 0. | ||
245 | + */ | ||
246 | + private final void normalize() { | ||
247 | + double invscale = 1.0/m22; | ||
248 | + m00 *= invscale; | ||
249 | + m01 *= invscale; | ||
250 | + m02 *= invscale; | ||
251 | + m10 *= invscale; | ||
252 | + m11 *= invscale; | ||
253 | + m12 *= invscale; | ||
254 | + m20 *= invscale; | ||
255 | + m21 *= invscale; | ||
256 | + m22 = 1.0; | ||
257 | + } | ||
258 | + | ||
259 | + private static final void getSquareToQuad(double x0, double y0, | ||
260 | + double x1, double y1, | ||
261 | + double x2, double y2, | ||
262 | + double x3, double y3, | ||
263 | + PerspectiveTransform tx) { | ||
264 | + double dx3 = x0 - x1 + x2 - x3; | ||
265 | + double dy3 = y0 - y1 + y2 - y3; | ||
266 | + | ||
267 | + tx.m22 = 1.0F; | ||
268 | + | ||
269 | + if ((dx3 == 0.0F) && (dy3 == 0.0F)) { // to do: use tolerance | ||
270 | + tx.m00 = x1 - x0; | ||
271 | + tx.m01 = x2 - x1; | ||
272 | + tx.m02 = x0; | ||
273 | + tx.m10 = y1 - y0; | ||
274 | + tx.m11 = y2 - y1; | ||
275 | + tx.m12 = y0; | ||
276 | + tx.m20 = 0.0F; | ||
277 | + tx.m21 = 0.0F; | ||
278 | + } else { | ||
279 | + double dx1 = x1 - x2; | ||
280 | + double dy1 = y1 - y2; | ||
281 | + double dx2 = x3 - x2; | ||
282 | + double dy2 = y3 - y2; | ||
283 | + | ||
284 | + double invdet = 1.0F/(dx1*dy2 - dx2*dy1); | ||
285 | + tx.m20 = (dx3*dy2 - dx2*dy3)*invdet; | ||
286 | + tx.m21 = (dx1*dy3 - dx3*dy1)*invdet; | ||
287 | + tx.m00 = x1 - x0 + tx.m20*x1; | ||
288 | + tx.m01 = x3 - x0 + tx.m21*x3; | ||
289 | + tx.m02 = x0; | ||
290 | + tx.m10 = y1 - y0 + tx.m20*y1; | ||
291 | + tx.m11 = y3 - y0 + tx.m21*y3; | ||
292 | + tx.m12 = y0; | ||
293 | + } | ||
294 | + } | ||
295 | + | ||
296 | + /** | ||
297 | + * Creates a PerspectiveTransform that maps the unit square | ||
298 | + * onto an arbitrary quadrilateral. | ||
299 | + * | ||
300 | + * <pre> | ||
301 | + * (0, 0) -> (x0, y0) | ||
302 | + * (1, 0) -> (x1, y1) | ||
303 | + * (1, 1) -> (x2, y2) | ||
304 | + * (0, 1) -> (x3, y3) | ||
305 | + * </pre> | ||
306 | + */ | ||
307 | + public static PerspectiveTransform getSquareToQuad(double x0, double y0, | ||
308 | + double x1, double y1, | ||
309 | + double x2, double y2, | ||
310 | + double x3, double y3) { | ||
311 | + PerspectiveTransform tx = new PerspectiveTransform(); | ||
312 | + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx); | ||
313 | + return tx; | ||
314 | + } | ||
315 | + | ||
316 | + | ||
317 | + /** | ||
318 | + * Creates a PerspectiveTransform that maps the unit square | ||
319 | + * onto an arbitrary quadrilateral. | ||
320 | + * | ||
321 | + * <pre> | ||
322 | + * (0, 0) -> (x0, y0) | ||
323 | + * (1, 0) -> (x1, y1) | ||
324 | + * (1, 1) -> (x2, y2) | ||
325 | + * (0, 1) -> (x3, y3) | ||
326 | + * </pre> | ||
327 | + */ | ||
328 | + public static PerspectiveTransform getSquareToQuad(float x0, float y0, | ||
329 | + float x1, float y1, | ||
330 | + float x2, float y2, | ||
331 | + float x3, float y3) { | ||
332 | + return getSquareToQuad((double)x0, (double)y0, | ||
333 | + (double)x1, (double)y1, | ||
334 | + (double)x2, (double)y2, | ||
335 | + (double)x3, (double)y3); | ||
336 | + } | ||
337 | + | ||
338 | + | ||
339 | + /** | ||
340 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
341 | + * quadrilateral onto the unit square. | ||
342 | + * | ||
343 | + * <pre> | ||
344 | + * (x0, y0) -> (0, 0) | ||
345 | + * (x1, y1) -> (1, 0) | ||
346 | + * (x2, y2) -> (1, 1) | ||
347 | + * (x3, y3) -> (0, 1) | ||
348 | + * </pre> | ||
349 | + */ | ||
350 | + public static PerspectiveTransform getQuadToSquare(double x0, double y0, | ||
351 | + double x1, double y1, | ||
352 | + double x2, double y2, | ||
353 | + double x3, double y3) { | ||
354 | + PerspectiveTransform tx = new PerspectiveTransform(); | ||
355 | + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx); | ||
356 | + tx.makeAdjoint(); | ||
357 | + return tx; | ||
358 | + } | ||
359 | + | ||
360 | + /** | ||
361 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
362 | + * quadrilateral onto the unit square. | ||
363 | + * | ||
364 | + * <pre> | ||
365 | + * (x0, y0) -> (0, 0) | ||
366 | + * (x1, y1) -> (1, 0) | ||
367 | + * (x2, y2) -> (1, 1) | ||
368 | + * (x3, y3) -> (0, 1) | ||
369 | + * </pre> | ||
370 | + */ | ||
371 | + public static PerspectiveTransform getQuadToSquare(float x0, float y0, | ||
372 | + float x1, float y1, | ||
373 | + float x2, float y2, | ||
374 | + float x3, float y3) { | ||
375 | + return getQuadToSquare((double)x0, (double)y0, | ||
376 | + (double)x1, (double)y1, | ||
377 | + (double)x2, (double)y2, | ||
378 | + (double)x3, (double)y3); | ||
379 | + } | ||
380 | + | ||
381 | + /** | ||
382 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
383 | + * quadrilateral onto another arbitrary quadrilateral. | ||
384 | + * | ||
385 | + * <pre> | ||
386 | + * (x0, y0) -> (x0p, y0p) | ||
387 | + * (x1, y1) -> (x1p, y1p) | ||
388 | + * (x2, y2) -> (x2p, y2p) | ||
389 | + * (x3, y3) -> (x3p, y3p) | ||
390 | + * </pre> | ||
391 | + */ | ||
392 | + public static PerspectiveTransform getQuadToQuad(double x0, double y0, | ||
393 | + double x1, double y1, | ||
394 | + double x2, double y2, | ||
395 | + double x3, double y3, | ||
396 | + double x0p, double y0p, | ||
397 | + double x1p, double y1p, | ||
398 | + double x2p, double y2p, | ||
399 | + double x3p, double y3p) { | ||
400 | + PerspectiveTransform tx1 = | ||
401 | + getQuadToSquare(x0, y0, x1, y1, x2, y2, x3, y3); | ||
402 | + | ||
403 | + PerspectiveTransform tx2 = | ||
404 | + getSquareToQuad(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); | ||
405 | + | ||
406 | + tx1.concatenate(tx2); | ||
407 | + return tx1; | ||
408 | + } | ||
409 | + | ||
410 | + | ||
411 | + /** | ||
412 | + * Creates a PerspectiveTransform that maps an arbitrary | ||
413 | + * quadrilateral onto another arbitrary quadrilateral. | ||
414 | + * | ||
415 | + * <pre> | ||
416 | + * (x0, y0) -> (x0p, y0p) | ||
417 | + * (x1, y1) -> (x1p, y1p) | ||
418 | + * (x2, y2) -> (x2p, y2p) | ||
419 | + * (x3, y3) -> (x3p, y3p) | ||
420 | + * </pre> | ||
421 | + */ | ||
422 | + public static PerspectiveTransform getQuadToQuad(float x0, float y0, | ||
423 | + float x1, float y1, | ||
424 | + float x2, float y2, | ||
425 | + float x3, float y3, | ||
426 | + float x0p, float y0p, | ||
427 | + float x1p, float y1p, | ||
428 | + float x2p, float y2p, | ||
429 | + float x3p, float y3p) { | ||
430 | + return getQuadToQuad((double)x0, (double)y0, | ||
431 | + (double)x1, (double)y1, | ||
432 | + (double)x2, (double)y2, | ||
433 | + (double)x3, (double)y3, | ||
434 | + (double)x0p, (double)y0p, | ||
435 | + (double)x1p, (double)y1p, | ||
436 | + (double)x2p, (double)y2p, | ||
437 | + (double)x3p, (double)y3p); | ||
438 | + } | ||
439 | + | ||
440 | + /** | ||
441 | + * Returns the determinant of the matrix representation of the | ||
442 | + * transform. | ||
443 | + */ | ||
444 | + public double getDeterminant() { | ||
445 | + return ( (m00 * ((m11 * m22) - (m12 * m21))) - | ||
446 | + (m01 * ((m10 * m22) - (m12 * m20))) + | ||
447 | + (m02 * ((m10 * m21) - (m11 * m20))) ); | ||
448 | + | ||
449 | + } | ||
450 | + | ||
451 | + /** | ||
452 | + * Retrieves the 9 specifiable values in the 3x3 affine | ||
453 | + * transformation matrix into an array of double precision values. | ||
454 | + * The values are stored into the array as | ||
455 | + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }. | ||
456 | + * | ||
457 | + * @param flatmatrix The double array used to store the returned | ||
458 | + * values. The length of the array is assumed to be at | ||
459 | + * least 9. | ||
460 | + * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small | ||
461 | + * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead. | ||
462 | + */ | ||
463 | + public double[] getMatrix(double[] flatmatrix) { | ||
464 | + if (flatmatrix == null) { | ||
465 | + flatmatrix = new double[9]; | ||
466 | + } | ||
467 | + | ||
468 | + flatmatrix[0] = m00; | ||
469 | + flatmatrix[1] = m01; | ||
470 | + flatmatrix[2] = m02; | ||
471 | + flatmatrix[3] = m10; | ||
472 | + flatmatrix[4] = m11; | ||
473 | + flatmatrix[5] = m12; | ||
474 | + flatmatrix[6] = m20; | ||
475 | + flatmatrix[7] = m21; | ||
476 | + flatmatrix[8] = m22; | ||
477 | + | ||
478 | + return flatmatrix; | ||
479 | + } | ||
480 | + | ||
481 | + /** | ||
482 | + * Retrieves the 9 specifiable values in the 3x3 affine | ||
483 | + * transformation matrix into a 2-dimensional array of double | ||
484 | + * precision values. The values are stored into the 2-dimensional | ||
485 | + * array using the row index as the first subscript and the column | ||
486 | + * index as the second. | ||
487 | + * | ||
488 | + * @param matrix The 2-dimensional double array to store the | ||
489 | + * returned values. The array is assumed to be at least 3x3. | ||
490 | + * @throws ArrayIndexOutOfBoundsException if matrix is too small | ||
491 | + */ | ||
492 | + public double[][] getMatrix(double[][] matrix) { | ||
493 | + if (matrix == null) { | ||
494 | + matrix = new double[3][3]; | ||
495 | + } | ||
496 | + | ||
497 | + matrix[0][0] = m00; | ||
498 | + matrix[0][1] = m01; | ||
499 | + matrix[0][2] = m02; | ||
500 | + matrix[1][0] = m10; | ||
501 | + matrix[1][1] = m11; | ||
502 | + matrix[1][2] = m12; | ||
503 | + matrix[2][0] = m20; | ||
504 | + matrix[2][1] = m21; | ||
505 | + matrix[2][2] = m22; | ||
506 | + | ||
507 | + return matrix; | ||
508 | + } | ||
509 | + | ||
510 | + /** | ||
511 | + * Concatenates this transform with a translation transformation. | ||
512 | + * This is equivalent to calling concatenate(T), where T is an | ||
513 | + * PerspectiveTransform represented by the following matrix: | ||
514 | + * <pre> | ||
515 | + * [ 1 0 tx ] | ||
516 | + * [ 0 1 ty ] | ||
517 | + * [ 0 0 1 ] | ||
518 | + * </pre> | ||
519 | + */ | ||
520 | + public void translate(double tx, double ty) { | ||
521 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
522 | + Tx.setToTranslation(tx, ty); | ||
523 | + concatenate(Tx); | ||
524 | + } | ||
525 | + | ||
526 | + /** | ||
527 | + * Concatenates this transform with a rotation transformation. | ||
528 | + * This is equivalent to calling concatenate(R), where R is an | ||
529 | + * PerspectiveTransform represented by the following matrix: | ||
530 | + * <pre> | ||
531 | + * [ cos(theta) -sin(theta) 0 ] | ||
532 | + * [ sin(theta) cos(theta) 0 ] | ||
533 | + * [ 0 0 1 ] | ||
534 | + * </pre> | ||
535 | + * Rotating with a positive angle theta rotates points on the positive | ||
536 | + * X axis toward the positive Y axis. | ||
537 | + * | ||
538 | + * @param theta The angle of rotation in radians. | ||
539 | + */ | ||
540 | + public void rotate(double theta) { | ||
541 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
542 | + Tx.setToRotation(theta); | ||
543 | + concatenate(Tx); | ||
544 | + } | ||
545 | + | ||
546 | + /** | ||
547 | + * Concatenates this transform with a translated rotation transformation. | ||
548 | + * This is equivalent to the following sequence of calls: | ||
549 | + * <pre> | ||
550 | + * translate(x, y); | ||
551 | + * rotate(theta); | ||
552 | + * translate(-x, -y); | ||
553 | + * </pre> | ||
554 | + * Rotating with a positive angle theta rotates points on the positive | ||
555 | + * X axis toward the positive Y axis. | ||
556 | + * | ||
557 | + * @param theta The angle of rotation in radians. | ||
558 | + * @param x The X coordinate of the origin of the rotation | ||
559 | + * @param y The Y coordinate of the origin of the rotation | ||
560 | + */ | ||
561 | + public void rotate(double theta, double x, double y) { | ||
562 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
563 | + Tx.setToRotation(theta, x, y); | ||
564 | + concatenate(Tx); | ||
565 | + } | ||
566 | + | ||
567 | + /** | ||
568 | + * Concatenates this transform with a scaling transformation. | ||
569 | + * This is equivalent to calling concatenate(S), where S is an | ||
570 | + * PerspectiveTransform represented by the following matrix: | ||
571 | + * <pre> | ||
572 | + * [ sx 0 0 ] | ||
573 | + * [ 0 sy 0 ] | ||
574 | + * [ 0 0 1 ] | ||
575 | + * </pre> | ||
576 | + * | ||
577 | + * @param sx The X axis scale factor. | ||
578 | + * @param sy The Y axis scale factor. | ||
579 | + */ | ||
580 | + public void scale(double sx, double sy) { | ||
581 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
582 | + Tx.setToScale(sx, sy); | ||
583 | + concatenate(Tx); | ||
584 | + } | ||
585 | + | ||
586 | + /** | ||
587 | + * Concatenates this transform with a shearing transformation. | ||
588 | + * This is equivalent to calling concatenate(SH), where SH is an | ||
589 | + * PerspectiveTransform represented by the following matrix: | ||
590 | + * <pre> | ||
591 | + * [ 1 shx 0 ] | ||
592 | + * [ shy 1 0 ] | ||
593 | + * [ 0 0 1 ] | ||
594 | + * </pre> | ||
595 | + * | ||
596 | + * @param shx The factor by which coordinates are shifted towards | ||
597 | + * the positive X axis direction according to their Y | ||
598 | + * coordinate. | ||
599 | + * @param shy The factor by which coordinates are shifted towards | ||
600 | + * the positive Y axis direction according to their X | ||
601 | + * coordinate. | ||
602 | + */ | ||
603 | + public void shear(double shx, double shy) { | ||
604 | + PerspectiveTransform Tx = new PerspectiveTransform(); | ||
605 | + Tx.setToShear(shx, shy); | ||
606 | + concatenate(Tx); | ||
607 | + } | ||
608 | + | ||
609 | + /** | ||
610 | + * Resets this transform to the Identity transform. | ||
611 | + */ | ||
612 | + public void setToIdentity() { | ||
613 | + m00 = m11 = m22 = 1.0; | ||
614 | + m01 = m10 = m02 = m20 = m12 = m21 = 0.0; | ||
615 | + } | ||
616 | + | ||
617 | + /** | ||
618 | + * Sets this transform to a translation transformation. | ||
619 | + * The matrix representing this transform becomes: | ||
620 | + * <pre> | ||
621 | + * [ 1 0 tx ] | ||
622 | + * [ 0 1 ty ] | ||
623 | + * [ 0 0 1 ] | ||
624 | + * </pre> | ||
625 | + * @param tx The distance by which coordinates are translated in the | ||
626 | + * X axis direction | ||
627 | + * @param ty The distance by which coordinates are translated in the | ||
628 | + * Y axis direction | ||
629 | + */ | ||
630 | + public void setToTranslation(double tx, double ty) { | ||
631 | + m00 = 1.0; | ||
632 | + m01 = 0.0; | ||
633 | + m02 = tx; | ||
634 | + m10 = 0.0; | ||
635 | + m11 = 1.0; | ||
636 | + m12 = ty; | ||
637 | + m20 = 0.0; | ||
638 | + m21 = 0.0; | ||
639 | + m22 = 1.0; | ||
640 | + } | ||
641 | + | ||
642 | + /** | ||
643 | + * Sets this transform to a rotation transformation. | ||
644 | + * The matrix representing this transform becomes: | ||
645 | + * <pre> | ||
646 | + * [ cos(theta) -sin(theta) 0 ] | ||
647 | + * [ sin(theta) cos(theta) 0 ] | ||
648 | + * [ 0 0 1 ] | ||
649 | + * </pre> | ||
650 | + * Rotating with a positive angle theta rotates points on the positive | ||
651 | + * X axis toward the positive Y axis. | ||
652 | + * @param theta The angle of rotation in radians. | ||
653 | + */ | ||
654 | + public void setToRotation(double theta) { | ||
655 | + m00 = Math.cos(theta); | ||
656 | + m01 = -Math.sin(theta); | ||
657 | + m02 = 0.0; | ||
658 | + m10 = - m01; // Math.sin(theta); | ||
659 | + m11 = m00; // Math.cos(theta); | ||
660 | + m12 = 0.0; | ||
661 | + m20 = 0.0; | ||
662 | + m21 = 0.0; | ||
663 | + m22 = 1.0; | ||
664 | + } | ||
665 | + | ||
666 | + /** | ||
667 | + * Sets this transform to a rotation transformation | ||
668 | + * about a specified point (x, y). This is equivalent | ||
669 | + * to the following sequence of calls: | ||
670 | + * | ||
671 | + * <pre> | ||
672 | + * setToTranslate(x, y); | ||
673 | + * rotate(theta); | ||
674 | + * translate(-x, -y); | ||
675 | + * </pre> | ||
676 | + * | ||
677 | + * Rotating with a positive angle theta rotates points on the positive | ||
678 | + * X axis toward the positive Y axis. | ||
679 | + * | ||
680 | + * @param theta The angle of rotation in radians. | ||
681 | + * @param x The X coordinate of the origin of the rotation | ||
682 | + * @param y The Y coordinate of the origin of the rotation | ||
683 | + */ | ||
684 | + public void setToRotation(double theta, double x, double y) { | ||
685 | + setToRotation(theta); | ||
686 | + double sin = m10; | ||
687 | + double oneMinusCos = 1.0 - m00; | ||
688 | + m02 = x * oneMinusCos + y * sin; | ||
689 | + m12 = y * oneMinusCos - x * sin; | ||
690 | + } | ||
691 | + | ||
692 | + /** | ||
693 | + * Sets this transform to a scale transformation | ||
694 | + * with scale factors sx and sy. | ||
695 | + * The matrix representing this transform becomes: | ||
696 | + * <pre> | ||
697 | + * [ sx 0 0 ] | ||
698 | + * [ 0 sy 0 ] | ||
699 | + * [ 0 0 1 ] | ||
700 | + * </pre> | ||
701 | + * | ||
702 | + * @param sx The X axis scale factor. | ||
703 | + * @param sy The Y axis scale factor. | ||
704 | + */ | ||
705 | + public void setToScale(double sx, double sy) { | ||
706 | + m00 = sx; | ||
707 | + m01 = 0.0; | ||
708 | + m02 = 0.0; | ||
709 | + m10 = 0.0; | ||
710 | + m11 = sy; | ||
711 | + m12 = 0.0; | ||
712 | + m20 = 0.0; | ||
713 | + m21 = 0.0; | ||
714 | + m22 = 1.0; | ||
715 | + } | ||
716 | + | ||
717 | + /** | ||
718 | + * Sets this transform to a shearing transformation | ||
719 | + * with shear factors sx and sy. | ||
720 | + * The matrix representing this transform becomes: | ||
721 | + * <pre> | ||
722 | + * [ 1 shx 0 ] | ||
723 | + * [ shy 1 0 ] | ||
724 | + * [ 0 0 1 ] | ||
725 | + * </pre> | ||
726 | + * | ||
727 | + * @param shx The factor by which coordinates are shifted towards | ||
728 | + * the positive X axis direction according to their Y | ||
729 | + * coordinate. | ||
730 | + * @param shy The factor by which coordinates are shifted towards | ||
731 | + * the positive Y axis direction according to their X | ||
732 | + * coordinate. | ||
733 | + */ | ||
734 | + public void setToShear(double shx, double shy) { | ||
735 | + m00 = 1.0; | ||
736 | + m01 = shx; | ||
737 | + m02 = 0.0; | ||
738 | + m10 = shy; | ||
739 | + m11 = 1.0; | ||
740 | + m12 = 0.0; | ||
741 | + m20 = 0.0; | ||
742 | + m21 = 0.0; | ||
743 | + m22 = 1.0; | ||
744 | + } | ||
745 | + | ||
746 | + /** | ||
747 | + * Sets this transform to a given AffineTransform. | ||
748 | + * @throws IllegalArgumentException if Tx is null | ||
749 | + */ | ||
750 | + public void setTransform(AffineTransform Tx) { | ||
751 | + if ( Tx == null ) { | ||
752 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
753 | + } | ||
754 | + | ||
755 | + m00 = Tx.getScaleX(); | ||
756 | + m01 = Tx.getShearX(); | ||
757 | + m02 = Tx.getTranslateX(); | ||
758 | + m10 = Tx.getShearY(); | ||
759 | + m11 = Tx.getScaleY(); | ||
760 | + m12 = Tx.getTranslateY(); | ||
761 | + m20 = 0.0; | ||
762 | + m21 = 0.0; | ||
763 | + m22 = 1.0; | ||
764 | + } | ||
765 | + | ||
766 | + /** | ||
767 | + * Sets this transform to a given PerspectiveTransform. | ||
768 | + * @throws IllegalArgumentException if Tx is null | ||
769 | + */ | ||
770 | + public void setTransform(PerspectiveTransform Tx) { | ||
771 | + if ( Tx == null ) { | ||
772 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
773 | + } | ||
774 | + | ||
775 | + m00 = Tx.m00; | ||
776 | + m01 = Tx.m01; | ||
777 | + m02 = Tx.m02; | ||
778 | + m10 = Tx.m10; | ||
779 | + m11 = Tx.m11; | ||
780 | + m12 = Tx.m12; | ||
781 | + m20 = Tx.m20; | ||
782 | + m21 = Tx.m21; | ||
783 | + m22 = Tx.m22; | ||
784 | + } | ||
785 | + | ||
786 | + /** | ||
787 | + * Sets this transform to a given PerspectiveTransform, | ||
788 | + * expressed by the elements of its matrix. <i>Important Note: The | ||
789 | + * matrix elements in the argument list are in column-major order | ||
790 | + * unlike those of the constructor, which are in row-major order.</i> | ||
791 | + * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead. | ||
792 | + */ | ||
793 | + public void setTransform(float m00, float m10, float m20, | ||
794 | + float m01, float m11, float m21, | ||
795 | + float m02, float m12, float m22) { | ||
796 | + this.m00 = (double)m00; | ||
797 | + this.m01 = (double)m01; | ||
798 | + this.m02 = (double)m02; | ||
799 | + this.m10 = (double)m10; | ||
800 | + this.m11 = (double)m11; | ||
801 | + this.m12 = (double)m12; | ||
802 | + this.m20 = (double)m20; | ||
803 | + this.m21 = (double)m21; | ||
804 | + this.m22 = (double)m22; | ||
805 | + } | ||
806 | + | ||
807 | + /** | ||
808 | + * Sets this transform using a two-dimensional array of double precision | ||
809 | + * values. The row index is first, and the column index is second. | ||
810 | + * | ||
811 | + * @param matrix The 2D double array to be used for setting this transform. | ||
812 | + * The array is assumed to be at least 3x3. | ||
813 | + * @throws IllegalArgumentException if matrix is null | ||
814 | + * @throws ArrayIndexOutOfBoundsException if matrix is too small | ||
815 | + * @since JAI 1.1 | ||
816 | + */ | ||
817 | + public void setTransform(double[][] matrix) { | ||
818 | + if ( matrix == null ) { | ||
819 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
820 | + } | ||
821 | + | ||
822 | + m00 = matrix[0][0]; | ||
823 | + m01 = matrix[0][1]; | ||
824 | + m02 = matrix[0][2]; | ||
825 | + m10 = matrix[1][0]; | ||
826 | + m11 = matrix[1][1]; | ||
827 | + m12 = matrix[1][2]; | ||
828 | + m20 = matrix[2][0]; | ||
829 | + m21 = matrix[2][1]; | ||
830 | + m22 = matrix[2][2]; | ||
831 | + } | ||
832 | + | ||
833 | + /** | ||
834 | + * Post-concatenates a given AffineTransform to this transform. | ||
835 | + * @throws IllegalArgumentException if Tx is null | ||
836 | + */ | ||
837 | + public void concatenate(AffineTransform Tx) { | ||
838 | + if ( Tx == null ) { | ||
839 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
840 | + } | ||
841 | + | ||
842 | + // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1 | ||
843 | + | ||
844 | + double tx_m00 = Tx.getScaleX(); | ||
845 | + double tx_m01 = Tx.getShearX(); | ||
846 | + double tx_m02 = Tx.getTranslateX(); | ||
847 | + double tx_m10 = Tx.getShearY(); | ||
848 | + double tx_m11 = Tx.getScaleY(); | ||
849 | + double tx_m12 = Tx.getTranslateY(); | ||
850 | + | ||
851 | + double m00p = m00*tx_m00 + m10*tx_m01 + m20*tx_m02; | ||
852 | + double m01p = m01*tx_m00 + m11*tx_m01 + m21*tx_m02; | ||
853 | + double m02p = m02*tx_m00 + m12*tx_m01 + m22*tx_m02; | ||
854 | + double m10p = m00*tx_m10 + m10*tx_m11 + m20*tx_m12; | ||
855 | + double m11p = m01*tx_m10 + m11*tx_m11 + m21*tx_m12; | ||
856 | + double m12p = m02*tx_m10 + m12*tx_m11 + m22*tx_m12; | ||
857 | + double m20p = m20; | ||
858 | + double m21p = m21; | ||
859 | + double m22p = m22; | ||
860 | + | ||
861 | + m00 = m00p; | ||
862 | + m10 = m10p; | ||
863 | + m20 = m20p; | ||
864 | + m01 = m01p; | ||
865 | + m11 = m11p; | ||
866 | + m21 = m21p; | ||
867 | + m02 = m02p; | ||
868 | + m12 = m12p; | ||
869 | + m22 = m22p; | ||
870 | + } | ||
871 | + | ||
872 | + /** | ||
873 | + * Post-concatenates a given PerspectiveTransform to this transform. | ||
874 | + * @throws IllegalArgumentException if Tx is null | ||
875 | + */ | ||
876 | + public void concatenate(PerspectiveTransform Tx) { | ||
877 | + if ( Tx == null ) { | ||
878 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
879 | + } | ||
880 | + | ||
881 | + double m00p = m00*Tx.m00 + m10*Tx.m01 + m20*Tx.m02; | ||
882 | + double m10p = m00*Tx.m10 + m10*Tx.m11 + m20*Tx.m12; | ||
883 | + double m20p = m00*Tx.m20 + m10*Tx.m21 + m20*Tx.m22; | ||
884 | + double m01p = m01*Tx.m00 + m11*Tx.m01 + m21*Tx.m02; | ||
885 | + double m11p = m01*Tx.m10 + m11*Tx.m11 + m21*Tx.m12; | ||
886 | + double m21p = m01*Tx.m20 + m11*Tx.m21 + m21*Tx.m22; | ||
887 | + double m02p = m02*Tx.m00 + m12*Tx.m01 + m22*Tx.m02; | ||
888 | + double m12p = m02*Tx.m10 + m12*Tx.m11 + m22*Tx.m12; | ||
889 | + double m22p = m02*Tx.m20 + m12*Tx.m21 + m22*Tx.m22; | ||
890 | + | ||
891 | + m00 = m00p; | ||
892 | + m10 = m10p; | ||
893 | + m20 = m20p; | ||
894 | + m01 = m01p; | ||
895 | + m11 = m11p; | ||
896 | + m21 = m21p; | ||
897 | + m02 = m02p; | ||
898 | + m12 = m12p; | ||
899 | + m22 = m22p; | ||
900 | + } | ||
901 | + | ||
902 | + /** | ||
903 | + * Pre-concatenates a given AffineTransform to this transform. | ||
904 | + * @throws IllegalArgumentException if Tx is null | ||
905 | + */ | ||
906 | + public void preConcatenate(AffineTransform Tx) { | ||
907 | + if ( Tx == null ) { | ||
908 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
909 | + } | ||
910 | + | ||
911 | + // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1 | ||
912 | + | ||
913 | + double tx_m00 = Tx.getScaleX(); | ||
914 | + double tx_m01 = Tx.getShearX(); | ||
915 | + double tx_m02 = Tx.getTranslateX(); | ||
916 | + double tx_m10 = Tx.getShearY(); | ||
917 | + double tx_m11 = Tx.getScaleY(); | ||
918 | + double tx_m12 = Tx.getTranslateY(); | ||
919 | + | ||
920 | + double m00p = tx_m00*m00 + tx_m10*m01; | ||
921 | + double m01p = tx_m01*m00 + tx_m11*m01; | ||
922 | + double m02p = tx_m02*m00 + tx_m12*m01 + m02; | ||
923 | + double m10p = tx_m00*m10 + tx_m10*m11; | ||
924 | + double m11p = tx_m01*m10 + tx_m11*m11; | ||
925 | + double m12p = tx_m02*m10 + tx_m12*m11 + m12; | ||
926 | + double m20p = tx_m00*m20 + tx_m10*m21; | ||
927 | + double m21p = tx_m01*m20 + tx_m11*m21; | ||
928 | + double m22p = tx_m02*m20 + tx_m12*m21 + m22; | ||
929 | + | ||
930 | + m00 = m00p; | ||
931 | + m10 = m10p; | ||
932 | + m20 = m20p; | ||
933 | + m01 = m01p; | ||
934 | + m11 = m11p; | ||
935 | + m21 = m21p; | ||
936 | + m02 = m02p; | ||
937 | + m12 = m12p; | ||
938 | + m22 = m22p; | ||
939 | + } | ||
940 | + | ||
941 | + /** | ||
942 | + * Pre-concatenates a given PerspectiveTransform to this transform. | ||
943 | + * @throws IllegalArgumentException if Tx is null | ||
944 | + */ | ||
945 | + public void preConcatenate(PerspectiveTransform Tx) { | ||
946 | + if ( Tx == null ) { | ||
947 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
948 | + } | ||
949 | + | ||
950 | + double m00p = Tx.m00*m00 + Tx.m10*m01 + Tx.m20*m02; | ||
951 | + double m10p = Tx.m00*m10 + Tx.m10*m11 + Tx.m20*m12; | ||
952 | + double m20p = Tx.m00*m20 + Tx.m10*m21 + Tx.m20*m22; | ||
953 | + double m01p = Tx.m01*m00 + Tx.m11*m01 + Tx.m21*m02; | ||
954 | + double m11p = Tx.m01*m10 + Tx.m11*m11 + Tx.m21*m12; | ||
955 | + double m21p = Tx.m01*m20 + Tx.m11*m21 + Tx.m21*m22; | ||
956 | + double m02p = Tx.m02*m00 + Tx.m12*m01 + Tx.m22*m02; | ||
957 | + double m12p = Tx.m02*m10 + Tx.m12*m11 + Tx.m22*m12; | ||
958 | + double m22p = Tx.m02*m20 + Tx.m12*m21 + Tx.m22*m22; | ||
959 | + | ||
960 | + m00 = m00p; | ||
961 | + m10 = m10p; | ||
962 | + m20 = m20p; | ||
963 | + m01 = m01p; | ||
964 | + m11 = m11p; | ||
965 | + m21 = m21p; | ||
966 | + m02 = m02p; | ||
967 | + m12 = m12p; | ||
968 | + m22 = m22p; | ||
969 | + } | ||
970 | + | ||
971 | + /** | ||
972 | + * Returns a new PerpectiveTransform that is the inverse | ||
973 | + * of the current transform. | ||
974 | + * @throws NoninvertibleTransformException if transform cannot be inverted | ||
975 | + */ | ||
976 | + public PerspectiveTransform createInverse() | ||
977 | + throws NoninvertibleTransformException, CloneNotSupportedException { | ||
978 | + | ||
979 | + PerspectiveTransform tx = (PerspectiveTransform)clone(); | ||
980 | + tx.makeAdjoint(); | ||
981 | + if (Math.abs(tx.m22) < PERSPECTIVE_DIVIDE_EPSILON) { | ||
982 | + throw new NoninvertibleTransformException(JaiI18N.getString("PerspectiveTransform0")); | ||
983 | + } | ||
984 | + tx.normalize(); | ||
985 | + return tx; | ||
986 | + } | ||
987 | + | ||
988 | + /** | ||
989 | + * Returns a new PerpectiveTransform that is the adjoint, | ||
990 | + * of the current transform. The adjoint is defined as | ||
991 | + * the matrix of cofactors, which in turn are the determinants | ||
992 | + * of the submatrices defined by removing the row and column | ||
993 | + * of each element from the original matrix in turn. | ||
994 | + * | ||
995 | + * <p> The adjoint is a scalar multiple of the inverse matrix. | ||
996 | + * Because points to be transformed are converted into homogeneous | ||
997 | + * coordinates, where scalar factors are irrelevant, the adjoint | ||
998 | + * may be used in place of the true inverse. Since it is unnecessary | ||
999 | + * to normalize the adjoint, it is both faster to compute and more | ||
1000 | + * numerically stable than the true inverse. | ||
1001 | + */ | ||
1002 | + public PerspectiveTransform createAdjoint() | ||
1003 | + throws CloneNotSupportedException{ | ||
1004 | + | ||
1005 | + PerspectiveTransform tx = (PerspectiveTransform)clone(); | ||
1006 | + tx.makeAdjoint(); | ||
1007 | + return tx; | ||
1008 | + } | ||
1009 | + | ||
1010 | + /** | ||
1011 | + * Transforms the specified ptSrc and stores the result in ptDst. | ||
1012 | + * If ptDst is null, a new Point2D object will be allocated before | ||
1013 | + * storing. In either case, ptDst containing the transformed point | ||
1014 | + * is returned for convenience. | ||
1015 | + * Note that ptSrc and ptDst can the same. In this case, the input | ||
1016 | + * point will be overwritten with the transformed point. | ||
1017 | + * | ||
1018 | + * @param ptSrc The array containing the source point objects. | ||
1019 | + * @param ptDst The array where the transform point objects are returned. | ||
1020 | + * @throws IllegalArgumentException if ptSrc is null | ||
1021 | + */ | ||
1022 | + public Point2D transform(Point2D ptSrc, Point2D ptDst) { | ||
1023 | + if ( ptSrc == null ) { | ||
1024 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1025 | + } | ||
1026 | + | ||
1027 | + if (ptDst == null) { | ||
1028 | + if (ptSrc instanceof Point2D.Double) { | ||
1029 | + ptDst = new Point2D.Double(); | ||
1030 | + } else { | ||
1031 | + ptDst = new Point2D.Float(); | ||
1032 | + } | ||
1033 | + } | ||
1034 | + | ||
1035 | + double x = ptSrc.getX(); | ||
1036 | + double y = ptSrc.getY(); | ||
1037 | + double w = m20 * x + m21 * y + m22; | ||
1038 | + ptDst.setLocation((m00 * x + m01 * y + m02) / w, | ||
1039 | + (m10 * x + m11 * y + m12) / w); | ||
1040 | + | ||
1041 | + return ptDst; | ||
1042 | + } | ||
1043 | + | ||
1044 | + /** | ||
1045 | + * Transforms an array of point objects by this transform. | ||
1046 | + * @param ptSrc The array containing the source point objects. | ||
1047 | + * @param ptDst The array where the transform point objects are returned. | ||
1048 | + * @param srcOff The offset to the first point object to be transformed | ||
1049 | + * in the source array. | ||
1050 | + * @param dstOff The offset to the location where the first transformed | ||
1051 | + * point object is stored in the destination array. | ||
1052 | + * @param numPts The number of point objects to be transformed. | ||
1053 | + * @throws IllegalArgumentException if ptSrc is null | ||
1054 | + * @throws IllegalArgumentException if ptDst is null | ||
1055 | + * @throws ArrayIndexOutOfBoundsException if ptSrc is too small | ||
1056 | + */ | ||
1057 | + public void transform(Point2D[] ptSrc, int srcOff, | ||
1058 | + Point2D[] ptDst, int dstOff, | ||
1059 | + int numPts) { | ||
1060 | + | ||
1061 | + if ( ptSrc == null || ptDst == null ) { | ||
1062 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1063 | + } | ||
1064 | + | ||
1065 | + while (numPts-- > 0) { | ||
1066 | + /* Copy source coords into local variables in case src == dst. */ | ||
1067 | + Point2D src = ptSrc[srcOff++]; | ||
1068 | + Point2D dst = ptDst[dstOff++]; | ||
1069 | + if (dst == null) { | ||
1070 | + if (src instanceof Point2D.Double) { | ||
1071 | + dst = new Point2D.Double(); | ||
1072 | + } else { | ||
1073 | + dst = new Point2D.Float(); | ||
1074 | + } | ||
1075 | + ptDst[dstOff - 1] = dst; | ||
1076 | + } | ||
1077 | + | ||
1078 | + double x = src.getX(); | ||
1079 | + double y = src.getY(); | ||
1080 | + double w = m20 * x + m21 * y + m22; | ||
1081 | + | ||
1082 | + if (w == 0) { | ||
1083 | + dst.setLocation(x, y); | ||
1084 | + } else { | ||
1085 | + dst.setLocation((m00 * x + m01 * y + m02) / w, | ||
1086 | + (m10 * x + m11 * y + m12) / w); | ||
1087 | + } | ||
1088 | + } | ||
1089 | + } | ||
1090 | + | ||
1091 | + /** | ||
1092 | + * Transforms an array of floating point coordinates by this transform. | ||
1093 | + * @param srcPts The array containing the source point coordinates. | ||
1094 | + * Each point is stored as a pair of x,y coordinates. | ||
1095 | + * @param srcOff The offset to the first point to be transformed | ||
1096 | + * in the source array. | ||
1097 | + * @param dstPts The array where the transformed point coordinates are | ||
1098 | + * returned. Each point is stored as a pair of x,y coordinates. | ||
1099 | + * @param dstOff The offset to the location where the first transformed | ||
1100 | + * point is stored in the destination array. | ||
1101 | + * @param numPts The number of points to be transformed. | ||
1102 | + * @throws IllegalArgumentException if srcPts is null | ||
1103 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
1104 | + */ | ||
1105 | + public void transform(float[] srcPts, int srcOff, | ||
1106 | + float[] dstPts, int dstOff, | ||
1107 | + int numPts) { | ||
1108 | + | ||
1109 | + if ( srcPts == null ) { | ||
1110 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1111 | + } | ||
1112 | + | ||
1113 | + if (dstPts == null) { | ||
1114 | + dstPts = new float[numPts * 2 + dstOff]; | ||
1115 | + } | ||
1116 | + | ||
1117 | + while (numPts-- > 0) { | ||
1118 | + float x = srcPts[srcOff++]; | ||
1119 | + float y = srcPts[srcOff++]; | ||
1120 | + double w = m20 * x + m21 * y + m22; | ||
1121 | + | ||
1122 | + if (w == 0) { | ||
1123 | + dstPts[dstOff++] = x; | ||
1124 | + dstPts[dstOff++] = y; | ||
1125 | + } else { | ||
1126 | + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w); | ||
1127 | + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w); | ||
1128 | + } | ||
1129 | + } | ||
1130 | + } | ||
1131 | + | ||
1132 | + /** | ||
1133 | + * Transforms an array of double precision coordinates by this transform. | ||
1134 | + * @param srcPts The array containing the source point coordinates. | ||
1135 | + * Each point is stored as a pair of x,y coordinates. | ||
1136 | + * @param dstPts The array where the transformed point coordinates are | ||
1137 | + * returned. Each point is stored as a pair of x,y coordinates. | ||
1138 | + * @param srcOff The offset to the first point to be transformed | ||
1139 | + * in the source array. | ||
1140 | + * @param dstOff The offset to the location where the first transformed | ||
1141 | + * point is stored in the destination array. | ||
1142 | + * @param numPts The number of point objects to be transformed. | ||
1143 | + * @throws IllegalArgumentException if srcPts is null | ||
1144 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
1145 | + */ | ||
1146 | + public void transform(double[] srcPts, int srcOff, | ||
1147 | + double[] dstPts, int dstOff, | ||
1148 | + int numPts) { | ||
1149 | + | ||
1150 | + if ( srcPts == null ) { | ||
1151 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1152 | + } | ||
1153 | + | ||
1154 | + if (dstPts == null) { | ||
1155 | + dstPts = new double[numPts * 2 + dstOff]; | ||
1156 | + } | ||
1157 | + | ||
1158 | + while (numPts-- > 0) { | ||
1159 | + double x = srcPts[srcOff++]; | ||
1160 | + double y = srcPts[srcOff++]; | ||
1161 | + double w = m20 * x + m21 * y + m22; | ||
1162 | + | ||
1163 | + if (w == 0) { | ||
1164 | + dstPts[dstOff++] = x; | ||
1165 | + dstPts[dstOff++] = y; | ||
1166 | + } else { | ||
1167 | + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w; | ||
1168 | + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w; | ||
1169 | + } | ||
1170 | + } | ||
1171 | + } | ||
1172 | + | ||
1173 | + /** | ||
1174 | + * Transforms an array of floating point coordinates by this transform, | ||
1175 | + * storing the results into an array of doubles. | ||
1176 | + * @param srcPts The array containing the source point coordinates. | ||
1177 | + * Each point is stored as a pair of x,y coordinates. | ||
1178 | + * @param srcOff The offset to the first point to be transformed | ||
1179 | + * in the source array. | ||
1180 | + * @param dstPts The array where the transformed point coordinates are | ||
1181 | + * returned. Each point is stored as a pair of x,y coordinates. | ||
1182 | + * @param dstOff The offset to the location where the first transformed | ||
1183 | + * point is stored in the destination array. | ||
1184 | + * @param numPts The number of points to be transformed. | ||
1185 | + * @throws IllegalArgumentException if srcPts is null | ||
1186 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
1187 | + */ | ||
1188 | + public void transform(float[] srcPts, int srcOff, | ||
1189 | + double[] dstPts, int dstOff, | ||
1190 | + int numPts) { | ||
1191 | + | ||
1192 | + if ( srcPts == null ) { | ||
1193 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1194 | + } | ||
1195 | + | ||
1196 | + if (dstPts == null) { | ||
1197 | + dstPts = new double[numPts * 2 + dstOff]; | ||
1198 | + } | ||
1199 | + | ||
1200 | + while (numPts-- > 0) { | ||
1201 | + float x = srcPts[srcOff++]; | ||
1202 | + float y = srcPts[srcOff++]; | ||
1203 | + double w = m20 * x + m21 * y + m22; | ||
1204 | + | ||
1205 | + if (w == 0) { | ||
1206 | + dstPts[dstOff++] = x; | ||
1207 | + dstPts[dstOff++] = y; | ||
1208 | + } else { | ||
1209 | + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w; | ||
1210 | + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w; | ||
1211 | + } | ||
1212 | + } | ||
1213 | + } | ||
1214 | + | ||
1215 | + /** | ||
1216 | + * Transforms an array of double precision coordinates by this transform, | ||
1217 | + * storing the results into an array of floats. | ||
1218 | + * @param srcPts The array containing the source point coordinates. | ||
1219 | + * Each point is stored as a pair of x,y coordinates. | ||
1220 | + * @param dstPts The array where the transformed point coordinates are | ||
1221 | + * returned. Each point is stored as a pair of x,y coordinates. | ||
1222 | + * @param srcOff The offset to the first point to be transformed | ||
1223 | + * in the source array. | ||
1224 | + * @param dstOff The offset to the location where the first transformed | ||
1225 | + * point is stored in the destination array. | ||
1226 | + * @param numPts The number of point objects to be transformed. | ||
1227 | + * @throws IllegalArgumentException if srcPts is null | ||
1228 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
1229 | + */ | ||
1230 | + public void transform(double[] srcPts, int srcOff, | ||
1231 | + float[] dstPts, int dstOff, | ||
1232 | + int numPts) { | ||
1233 | + | ||
1234 | + if ( srcPts == null ) { | ||
1235 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1236 | + } | ||
1237 | + | ||
1238 | + if (dstPts == null) { | ||
1239 | + dstPts = new float[numPts * 2 + dstOff]; | ||
1240 | + } | ||
1241 | + | ||
1242 | + while (numPts-- > 0) { | ||
1243 | + double x = srcPts[srcOff++]; | ||
1244 | + double y = srcPts[srcOff++]; | ||
1245 | + double w = m20 * x + m21 * y + m22; | ||
1246 | + | ||
1247 | + if (w == 0) { | ||
1248 | + dstPts[dstOff++] = (float)x; | ||
1249 | + dstPts[dstOff++] = (float)y; | ||
1250 | + } else { | ||
1251 | + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w); | ||
1252 | + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w); | ||
1253 | + } | ||
1254 | + } | ||
1255 | + } | ||
1256 | + | ||
1257 | + /** | ||
1258 | + * Inverse transforms the specified ptSrc and stores the result in ptDst. | ||
1259 | + * If ptDst is null, a new Point2D object will be allocated before | ||
1260 | + * storing. In either case, ptDst containing the transformed point | ||
1261 | + * is returned for convenience. | ||
1262 | + * Note that ptSrc and ptDst can the same. In this case, the input | ||
1263 | + * point will be overwritten with the transformed point. | ||
1264 | + * @param ptSrc The point to be inverse transformed. | ||
1265 | + * @param ptDst The resulting transformed point. | ||
1266 | + * @throws NoninvertibleTransformException if the matrix cannot be | ||
1267 | + * inverted. | ||
1268 | + * @throws IllegalArgumentException if ptSrc is null | ||
1269 | + */ | ||
1270 | + public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) | ||
1271 | + throws NoninvertibleTransformException | ||
1272 | + { | ||
1273 | + if ( ptSrc == null ) { | ||
1274 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1275 | + } | ||
1276 | + | ||
1277 | + if (ptDst == null) { | ||
1278 | + if (ptSrc instanceof Point2D.Double) { | ||
1279 | + ptDst = new Point2D.Double(); | ||
1280 | + } else { | ||
1281 | + ptDst = new Point2D.Float(); | ||
1282 | + } | ||
1283 | + } | ||
1284 | + // Copy source coords into local variables in case src == dst | ||
1285 | + double x = ptSrc.getX(); | ||
1286 | + double y = ptSrc.getY(); | ||
1287 | + | ||
1288 | + double tmp_x = (m11*m22 - m12*m21) * x + | ||
1289 | + (m02*m21 - m01*m22) * y + | ||
1290 | + (m01*m12 - m02*m11); | ||
1291 | + double tmp_y = (m12*m20 - m10*m22) * x + | ||
1292 | + (m00*m22 - m02*m20) * y + | ||
1293 | + (m02*m10 - m00*m12); | ||
1294 | + double w = (m10*m21 - m11*m20) * x + | ||
1295 | + (m01*m20 - m00*m21) * y + | ||
1296 | + (m00*m11 - m01*m10); | ||
1297 | + | ||
1298 | + double wabs = w; | ||
1299 | + if (w < 0) { | ||
1300 | + wabs = - w; | ||
1301 | + } | ||
1302 | + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) { | ||
1303 | + throw new | ||
1304 | + NoninvertibleTransformException( | ||
1305 | + JaiI18N.getString("PerspectiveTransform1")); | ||
1306 | + } | ||
1307 | + | ||
1308 | + ptDst.setLocation(tmp_x/w, tmp_y/w); | ||
1309 | + | ||
1310 | + return ptDst; | ||
1311 | + } | ||
1312 | + | ||
1313 | + /** | ||
1314 | + * Inverse transforms an array of double precision coordinates by | ||
1315 | + * this transform. | ||
1316 | + * @param srcPts The array containing the source point coordinates. | ||
1317 | + * Each point is stored as a pair of x,y coordinates. | ||
1318 | + * @param dstPts The array where the transformed point coordinates are | ||
1319 | + * returned. Each point is stored as a pair of x,y coordinates. | ||
1320 | + * @param srcOff The offset to the first point to be transformed | ||
1321 | + * in the source array. | ||
1322 | + * @param dstOff The offset to the location where the first transformed | ||
1323 | + * point is stored in the destination array. | ||
1324 | + * @param numPts The number of point objects to be transformed. | ||
1325 | + * @throws NoninvertibleTransformException if the matrix cannot be | ||
1326 | + * inverted. | ||
1327 | + * @throws IllegalArgumentException if srcPts is null | ||
1328 | + * @throws ArrayIndexOutOfBoundsException if srcPts is too small | ||
1329 | + * @throws NoninvertibleTransformException transform cannot be inverted | ||
1330 | + */ | ||
1331 | + public void inverseTransform(double[] srcPts, int srcOff, | ||
1332 | + double[] dstPts, int dstOff, | ||
1333 | + int numPts) | ||
1334 | + throws NoninvertibleTransformException | ||
1335 | + { | ||
1336 | + if ( srcPts == null ) { | ||
1337 | + throw new IllegalArgumentException(JaiI18N.getString("Generic0")); | ||
1338 | + } | ||
1339 | + | ||
1340 | + if (dstPts == null) { | ||
1341 | + dstPts = new double[numPts * 2 + dstOff]; | ||
1342 | + } | ||
1343 | + | ||
1344 | + while (numPts-- > 0) { | ||
1345 | + double x = srcPts[srcOff++]; | ||
1346 | + double y = srcPts[srcOff++]; | ||
1347 | + | ||
1348 | + double tmp_x = (m11*m22 - m12*m21) * x + | ||
1349 | + (m02*m21 - m01*m22) * y + | ||
1350 | + (m01*m12 - m02*m11); | ||
1351 | + double tmp_y = (m12*m20 - m10*m22) * x + | ||
1352 | + (m00*m22 - m02*m20) * y + | ||
1353 | + (m02*m10 - m00*m12); | ||
1354 | + double w = (m10*m21 - m11*m20) * x + | ||
1355 | + (m01*m20 - m00*m21) * y + | ||
1356 | + (m00*m11 - m01*m10); | ||
1357 | + | ||
1358 | + double wabs = w; | ||
1359 | + if (w < 0) { | ||
1360 | + wabs = - w; | ||
1361 | + } | ||
1362 | + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) { | ||
1363 | + throw new NoninvertibleTransformException( | ||
1364 | + JaiI18N.getString("PerspectiveTransform1")); | ||
1365 | + } | ||
1366 | + | ||
1367 | + dstPts[dstOff++] = tmp_x / w; | ||
1368 | + dstPts[dstOff++] = tmp_y / w; | ||
1369 | + } | ||
1370 | + } | ||
1371 | + | ||
1372 | + /** | ||
1373 | + * Returns a String that represents the value of this Object. | ||
1374 | + */ | ||
1375 | + public String toString() { | ||
1376 | + StringBuffer sb = new StringBuffer(); | ||
1377 | + sb.append("Perspective transform matrix\n"); | ||
1378 | + sb.append(this.m00); | ||
1379 | + sb.append("\t"); | ||
1380 | + sb.append(this.m01); | ||
1381 | + sb.append("\t"); | ||
1382 | + sb.append(this.m02); | ||
1383 | + sb.append("\n"); | ||
1384 | + sb.append(this.m10); | ||
1385 | + sb.append("\t"); | ||
1386 | + sb.append(this.m11); | ||
1387 | + sb.append("\t"); | ||
1388 | + sb.append(this.m12); | ||
1389 | + sb.append("\n"); | ||
1390 | + sb.append(this.m20); | ||
1391 | + sb.append("\t"); | ||
1392 | + sb.append(this.m21); | ||
1393 | + sb.append("\t"); | ||
1394 | + sb.append(this.m22); | ||
1395 | + sb.append("\n"); | ||
1396 | + return new String(sb); | ||
1397 | + } | ||
1398 | + | ||
1399 | + /** | ||
1400 | + * Returns the boolean true value if this PerspectiveTransform is an | ||
1401 | + * identity transform. Returns false otherwise. | ||
1402 | + */ | ||
1403 | + public boolean isIdentity() { | ||
1404 | + return m01 == 0.0 && m02 == 0.0 && | ||
1405 | + m10 == 0.0 && m12 == 0.0 && | ||
1406 | + m20 == 0.0 && m21 == 0.0 && | ||
1407 | + m22 != 0.0 && m00/m22 == 1.0 && m11/m22 == 1.0; | ||
1408 | + } | ||
1409 | + | ||
1410 | + /** | ||
1411 | + * Returns a copy of this PerspectiveTransform object. | ||
1412 | + */ | ||
1413 | + public Object clone() { | ||
1414 | + try { | ||
1415 | + return super.clone(); | ||
1416 | + } catch (CloneNotSupportedException e) { | ||
1417 | + // this shouldn't happen, since we are Cloneable | ||
1418 | + throw new InternalError(); | ||
1419 | + } | ||
1420 | + } | ||
1421 | + | ||
1422 | + | ||
1423 | + /** | ||
1424 | + * Tests if this PerspectiveTransform equals a supplied one. | ||
1425 | + * | ||
1426 | + * @param obj The PerspectiveTransform to be compared to this one. | ||
1427 | + */ | ||
1428 | + public boolean equals(Object obj) { | ||
1429 | + if (!(obj instanceof PerspectiveTransform)) { | ||
1430 | + return false; | ||
1431 | + } | ||
1432 | + | ||
1433 | + PerspectiveTransform a = (PerspectiveTransform)obj; | ||
1434 | + | ||
1435 | + return ((m00 == a.m00) && (m10 == a.m10) && (m20 == a.m20) && | ||
1436 | + (m01 == a.m01) && (m11 == a.m11) && (m21 == a.m21) && | ||
1437 | + (m02 == a.m02) && (m12 == a.m12) && (m22 == a.m22)); | ||
1438 | + } | ||
1439 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteConnector.java
0 → 100644
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +package org.mote.wiimote.whiteboard; | ||
2 | + | ||
3 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
4 | + | ||
5 | +import wiiremotej.WiiRemote; | ||
6 | +import wiiremotej.WiiRemoteJ; | ||
7 | + | ||
8 | +public class WiimoteConnector { | ||
9 | + | ||
10 | + private WiimoteDataHandler dh; | ||
11 | + | ||
12 | + public WiimoteConnector(WiimoteDataHandler dh) { | ||
13 | + this.dh = dh; | ||
14 | + } | ||
15 | + | ||
16 | + public void connect() { | ||
17 | + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty()) { | ||
18 | + WiimoteWhiteboard.getLogger().info(String.format("Directly connecting to bluetooth address(es) %s.", WWPreferences.WIIMOTE_BT_ADDRESSES)); | ||
19 | + for (int i = 0; i < Math.min(WWPreferences.WIIMOTE_BT_ADDRESSES.size(), WWPreferences.WIIMOTES); i++) { | ||
20 | + connect(WWPreferences.WIIMOTE_BT_ADDRESSES.get(i)); | ||
21 | + } | ||
22 | + } else { | ||
23 | + WiiRemoteJ.findRemotes(dh, WWPreferences.WIIMOTES); | ||
24 | + } | ||
25 | + } | ||
26 | + | ||
27 | + private void connect(final String address) { | ||
28 | + new Thread(new Runnable() { | ||
29 | + private boolean done = false; | ||
30 | + public void run() { | ||
31 | + while (!done) { | ||
32 | + try { | ||
33 | + WiiRemote r = WiiRemoteJ.connectToRemote(address); | ||
34 | + if (r != null && r.isConnected()) { | ||
35 | + done = true; | ||
36 | + dh.addRemote(r); | ||
37 | + } | ||
38 | + } catch (Exception e) { | ||
39 | + | ||
40 | + try { | ||
41 | + Thread.sleep(1000); | ||
42 | + } catch (InterruptedException e1) { | ||
43 | + e1.printStackTrace(); | ||
44 | + } | ||
45 | + } | ||
46 | + } | ||
47 | + } | ||
48 | + }).start(); | ||
49 | + } | ||
50 | + | ||
51 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteConnector.java~
0 → 100644
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +package org.mote.wiimote.whiteboard; | ||
2 | + | ||
3 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
4 | + | ||
5 | +import wiiremotej.WiiRemote; | ||
6 | +import wiiremotej.WiiRemoteJ; | ||
7 | + | ||
8 | +public class WiimoteConnector { | ||
9 | + | ||
10 | + private WiimoteDataHandler dh; | ||
11 | + | ||
12 | + public WiimoteConnector(WiimoteDataHandler dh) { | ||
13 | + this.dh = dh; | ||
14 | + } | ||
15 | + | ||
16 | + public void connect() { | ||
17 | + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty()) { | ||
18 | + WiimoteWhiteboard.getLogger().info(String.format("Directly connecting to bluetooth address(es) %s.", WWPreferences.WIIMOTE_BT_ADDRESSES)); | ||
19 | + for (int i = 0; i < Math.min(WWPreferences.WIIMOTE_BT_ADDRESSES.size(), WWPreferences.WIIMOTES); i++) { | ||
20 | + connect(WWPreferences.WIIMOTE_BT_ADDRESSES.get(i)); | ||
21 | + } | ||
22 | + } else { | ||
23 | + WiiRemoteJ.findRemotes(dh, WWPreferences.WIIMOTES); | ||
24 | + } | ||
25 | + } | ||
26 | + | ||
27 | + private void connect(final String address) { | ||
28 | + new Thread(new Runnable() { | ||
29 | + private boolean done = false; | ||
30 | + public void run() { | ||
31 | + while (!done) { | ||
32 | + try { | ||
33 | + WiiRemote r = WiiRemoteJ.connectToRemote(address); | ||
34 | + if (r != null && r.isConnected()) { | ||
35 | + done = true; | ||
36 | + dh.addRemote(r); | ||
37 | + } | ||
38 | + } catch (Exception e) { | ||
39 | +// if (e.getCause().getMessage().startsWith("Failed to open baseband connection")) { | ||
40 | +// // apparently simple timeout error | ||
41 | +// } else { | ||
42 | +// // "regular" connection error | ||
43 | +// } | ||
44 | + try { | ||
45 | + Thread.sleep(1000); | ||
46 | + } catch (InterruptedException e1) { | ||
47 | + e1.printStackTrace(); | ||
48 | + } | ||
49 | + } | ||
50 | + } | ||
51 | + } | ||
52 | + }).start(); | ||
53 | + } | ||
54 | + | ||
55 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteDataHandler.java
0 → 100644
@@ -0,0 +1,314 @@ | @@ -0,0 +1,314 @@ | ||
1 | +package org.mote.wiimote.whiteboard; | ||
2 | + | ||
3 | +import java.awt.Point; | ||
4 | +import java.util.Collection; | ||
5 | +import java.util.Collections; | ||
6 | +import java.util.EventObject; | ||
7 | +import java.util.HashSet; | ||
8 | +import java.util.LinkedHashMap; | ||
9 | +import java.util.Map; | ||
10 | +import java.util.Set; | ||
11 | +import java.util.logging.Level; | ||
12 | + | ||
13 | +import org.jdesktop.application.Application; | ||
14 | +import org.jdesktop.application.Application.ExitListener; | ||
15 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
16 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
17 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
18 | +import org.mote.wiimote.whiteboard.mouse.CursorControlStrategy; | ||
19 | +import org.mote.wiimote.whiteboard.mouse.Mouse; | ||
20 | +import org.mote.wiimote.whiteboard.mouse.smoothing.MouseSmoothingStrategy; | ||
21 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
22 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences.PreferencesListener; | ||
23 | + | ||
24 | +import wiiremotej.WiiRemote; | ||
25 | +import wiiremotej.WiiRemoteJ; | ||
26 | +import wiiremotej.event.WRButtonEvent; | ||
27 | +import wiiremotej.event.WRIREvent; | ||
28 | +import wiiremotej.event.WRStatusEvent; | ||
29 | +import wiiremotej.event.WiiDeviceDiscoveredEvent; | ||
30 | +import wiiremotej.event.WiiDeviceDiscoveryListener; | ||
31 | +import wiiremotej.event.WiiRemoteAdapter; | ||
32 | + | ||
33 | +public class WiimoteDataHandler extends WiiRemoteAdapter implements ExitListener, WiiDeviceDiscoveryListener, PreferencesListener { | ||
34 | + | ||
35 | + public static interface WiimoteDataListener { | ||
36 | + public void wiimoteConnected(Wiimote wiimote); | ||
37 | + public void wiimoteDisconnected(Wiimote wiimote); | ||
38 | + public void irLights(Wiimote wiimote, IRDot[] lights); | ||
39 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped); | ||
40 | + public void batteryLevel(Wiimote wiimote, double level); | ||
41 | + } | ||
42 | + | ||
43 | + private Map<WiiRemote, Wiimote> remotes = new LinkedHashMap<WiiRemote, Wiimote>(WWPreferences.WIIMOTES, 1f); | ||
44 | + private Map<WiiRemote, WRIREvent> events = new LinkedHashMap<WiiRemote, WRIREvent>(WWPreferences.WIIMOTES, 1f); | ||
45 | + private final WiimoteCalibration calibration; | ||
46 | + private static final WWPreferences prefs = WWPreferences.getPreferences(); | ||
47 | + private final Set<WiimoteDataListener> listener = Collections.synchronizedSet(new HashSet<WiimoteDataListener>()); | ||
48 | + | ||
49 | + private boolean cursorControl = true; | ||
50 | + | ||
51 | + private MouseSmoothingStrategy mss[] = new MouseSmoothingStrategy[4]; | ||
52 | + private CursorControlStrategy cursorControlStrategy; | ||
53 | + | ||
54 | + public WiimoteDataHandler(WiimoteCalibration calibration) { | ||
55 | + this.calibration = calibration; | ||
56 | + Application.getInstance().addExitListener(this); | ||
57 | + prefs.addPreferencesListener(this); | ||
58 | + preferencesChanged(); | ||
59 | + new WiimoteConnector(this).connect(); | ||
60 | + } | ||
61 | + | ||
62 | + public void enableIR(Wiimote wiimote) throws Exception { | ||
63 | + if (wiimote != null && wiimote.getWiiRemote().isConnected()) { | ||
64 | + wiimote.getWiiRemote().setIRSensorEnabled(true, WRIREvent.BASIC, WWPreferences.SENSITIVITY_SETTINGS); | ||
65 | + } | ||
66 | + WiimoteWhiteboard.getLogger().info(String.format("(Re-)Setting IR sensor of Wiimote %d: %s", wiimote.getId(), (wiimote != null && wiimote.getWiiRemote().isConnected() ? "done" : "not connected"))); | ||
67 | + } | ||
68 | + | ||
69 | + void addRemote(final WiiRemote remote) { | ||
70 | + try { | ||
71 | + int id = remotes.size()+1; | ||
72 | + final Wiimote wiimote = new Wiimote(remote, remote.getBluetoothAddress(), id); | ||
73 | + remotes.put(remote, wiimote); | ||
74 | + remote.setAccelerometerEnabled(false); | ||
75 | + enableIR(wiimote); | ||
76 | + remote.setLEDIlluminated(id-1, true); | ||
77 | + remote.setUseMouse(false); | ||
78 | + | ||
79 | + synchronized (listener) { | ||
80 | + for (WiimoteDataListener l : listener) | ||
81 | + l.wiimoteConnected(wiimote); | ||
82 | + } | ||
83 | + | ||
84 | + } catch (Exception e) { | ||
85 | + e.printStackTrace(); | ||
86 | + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Error on configuring Wii Remote", e); | ||
87 | + } | ||
88 | + | ||
89 | + remote.addWiiRemoteListener(this); | ||
90 | + | ||
91 | + // update battery level every minute | ||
92 | + new Thread(new Runnable() { | ||
93 | + public void run() { | ||
94 | + while (true) { | ||
95 | + try { | ||
96 | + // triggers #statusReported(WRStatusEvent) | ||
97 | + if (remote.isConnected()) | ||
98 | + remote.requestStatus(); | ||
99 | + } catch (Exception e) { | ||
100 | + e.printStackTrace(); | ||
101 | + WiimoteWhiteboard.getLogger().log(Level.WARNING, "Error on requesting status from Wii Remote", e); | ||
102 | + } | ||
103 | + try { | ||
104 | + Thread.sleep(60 * 1000); | ||
105 | + } catch (InterruptedException e) { | ||
106 | + e.printStackTrace(); | ||
107 | + } | ||
108 | + } | ||
109 | + } | ||
110 | + }).start(); | ||
111 | + } | ||
112 | + | ||
113 | + | ||
114 | + /* | ||
115 | + * EXIT | ||
116 | + */ | ||
117 | + | ||
118 | + public void willExit(EventObject event) { | ||
119 | + for (WiiRemote remote : remotes.keySet()) | ||
120 | + remote.disconnect(); | ||
121 | + } | ||
122 | + | ||
123 | + public boolean canExit(EventObject event) { | ||
124 | + return true; | ||
125 | + } | ||
126 | + | ||
127 | + | ||
128 | + /* | ||
129 | + * WIIREMOTEJ LISTENER | ||
130 | + */ | ||
131 | + | ||
132 | + @Override | ||
133 | + public synchronized void IRInputReceived(WRIREvent e) { | ||
134 | + events.put(e.getSource(), e); | ||
135 | + // wait till data from all connected wiimotes was received once and only process input on data from first wiimote to reduce the number of times the function gets called | ||
136 | + if (events.size() == getNumberOfConnectedWiimotes() && remotes.get(e.getSource()).getId() == 1) | ||
137 | + IRInputReceived(); | ||
138 | + } | ||
139 | + | ||
140 | + private void IRInputReceived() { | ||
141 | + boolean firstDotVisible = false; | ||
142 | + Map<Wiimote, IRDot[]> data = new LinkedHashMap<Wiimote, IRDot[]>(); | ||
143 | + for (WiiRemote r : events.keySet()) { | ||
144 | + Wiimote wiimote = remotes.get(r); | ||
145 | + IRDot[] dots = IRDot.getIRDots(events.get(r).getIRLights()); | ||
146 | + | ||
147 | + synchronized (listener) { | ||
148 | + for (WiimoteDataListener l : listener) | ||
149 | + l.irLights(wiimote, dots); | ||
150 | + } | ||
151 | + | ||
152 | + // exclude points from uncalibrated wiimotes during "normal operation" | ||
153 | + if (!calibration.isDone() || calibration.isCalibrated(wiimote)) { | ||
154 | + firstDotVisible = firstDotVisible || dots[0] != null; | ||
155 | + data.put(wiimote, dots); | ||
156 | + } | ||
157 | + } | ||
158 | + | ||
159 | + if (calibration.isDone()) { | ||
160 | + // should always be true, but just in case... | ||
161 | + if (calibration.isAnyCalibrated(data.keySet())) { | ||
162 | + Point warped[] = calibration.warp(data); | ||
163 | + for (int i = 0; i < 4; i++) { | ||
164 | + if (warped[i] != null) { | ||
165 | + warped[i] = mss[i].translate(warped[i]); | ||
166 | + } else { | ||
167 | + mss[i].reset(); | ||
168 | + } | ||
169 | + } | ||
170 | + | ||
171 | + if (isCursorControl()) { | ||
172 | + cursorControlStrategy.process(warped[0]); | ||
173 | + } else { | ||
174 | +// if (Mouse.LEFT_BUTTON.isPressed()) | ||
175 | + Mouse.LEFT_BUTTON.setPressed(false); | ||
176 | +// if (Mouse.RIGHT_BUTTON.isPressed()) | ||
177 | + Mouse.RIGHT_BUTTON.setPressed(false); | ||
178 | + } | ||
179 | + synchronized (listener) { | ||
180 | + for (WiimoteDataListener l : listener) | ||
181 | + l.irWarped(data, warped); | ||
182 | + } | ||
183 | + | ||
184 | + } | ||
185 | + } else if (calibration.inProgress()) { | ||
186 | + if (firstDotVisible) | ||
187 | + calibration.process(data); | ||
188 | + } | ||
189 | + | ||
190 | + } | ||
191 | + | ||
192 | + @Override | ||
193 | + public void statusReported(WRStatusEvent e) { | ||
194 | + synchronized (listener) { | ||
195 | + for (WiimoteDataListener l : listener) | ||
196 | + l.batteryLevel(remotes.get(e.getSource()), e.getBatteryLevel()); | ||
197 | + } | ||
198 | + } | ||
199 | + | ||
200 | + @Override | ||
201 | + public void buttonInputReceived(WRButtonEvent e) { | ||
202 | + if (e.isOnlyPressed(WRButtonEvent.A)) { | ||
203 | + calibration.start(getConnectedWiimotes()); | ||
204 | + } else if (e.isOnlyPressed(WRButtonEvent.HOME)) { | ||
205 | + Application.getInstance().exit(); | ||
206 | + } | ||
207 | + } | ||
208 | + | ||
209 | + public void wiiDeviceDiscovered(WiiDeviceDiscoveredEvent e) { | ||
210 | + if (e.getWiiDevice() instanceof WiiRemote) { | ||
211 | + addRemote((WiiRemote)e.getWiiDevice()); | ||
212 | + } | ||
213 | + } | ||
214 | + | ||
215 | + public void findFinished(int numberFound) { | ||
216 | + } | ||
217 | + | ||
218 | + @Override | ||
219 | + public void disconnected() { | ||
220 | + WiiRemoteJ.stopFind(); | ||
221 | + WiiRemote remove = null; | ||
222 | + for (WiiRemote remote : remotes.keySet()) { | ||
223 | + if (!remote.isConnected()) { | ||
224 | + remove = remote; | ||
225 | + synchronized (listener) { | ||
226 | + for (WiimoteDataListener l : listener) | ||
227 | + l.wiimoteDisconnected(remotes.get(remote)); | ||
228 | + } | ||
229 | + break; | ||
230 | + } | ||
231 | + } | ||
232 | + if (remove != null) remotes.remove(remove); | ||
233 | + } | ||
234 | + | ||
235 | + | ||
236 | + /* | ||
237 | + * LISTENER | ||
238 | + */ | ||
239 | + | ||
240 | + public void addWiimoteDataListener(WiimoteDataListener l) { | ||
241 | + listener.add(l); | ||
242 | + } | ||
243 | + | ||
244 | + public void removeWiimoteDataListener(WiimoteDataListener l) { | ||
245 | + listener.remove(l); | ||
246 | + } | ||
247 | + | ||
248 | + /* | ||
249 | + * PREFERENCES STUFF | ||
250 | + */ | ||
251 | + | ||
252 | + public void preferencesChanged() { | ||
253 | + updateMSS(); | ||
254 | + updateCursorControlStrategy(); | ||
255 | + | ||
256 | + @SuppressWarnings("unchecked") | ||
257 | + private void updateCursorControlStrategy() { | ||
258 | + if (cursorControlStrategy == null || !cursorControlStrategy.getClass().getName().equals(prefs.getCursorControl())) { | ||
259 | + try { | ||
260 | + Class<?> c = Class.forName(prefs.getCursorControl()); | ||
261 | + cursorControlStrategy = ((Class<? extends CursorControlStrategy>)c).newInstance(); | ||
262 | + } catch (Exception e) { | ||
263 | + e.printStackTrace(); | ||
264 | + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Cursor Control Method error.", e); | ||
265 | + } | ||
266 | + } | ||
267 | + } | ||
268 | + | ||
269 | + @SuppressWarnings("unchecked") | ||
270 | + private void updateMSS() { | ||
271 | + if (mss[0] == null || !mss[0].getClass().getName().equals(prefs.getMouseSmoothing())) { | ||
272 | + try { | ||
273 | + Class<?> c = Class.forName(prefs.getMouseSmoothing()); | ||
274 | + for (int i = 0; i < 4; i++) | ||
275 | + mss[i] = ((Class<? extends MouseSmoothingStrategy>)c).newInstance(); | ||
276 | + } catch (Exception e) { | ||
277 | + e.printStackTrace(); | ||
278 | + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Mouse Movement Smoothing error.", e); | ||
279 | + } | ||
280 | + } | ||
281 | + } | ||
282 | + | ||
283 | + /* | ||
284 | + * GETTER & SETTER | ||
285 | + */ | ||
286 | + | ||
287 | + public boolean isConnected() { | ||
288 | + for (WiiRemote remote : remotes.keySet()) { | ||
289 | + if (remote.isConnected()) return true; | ||
290 | + } | ||
291 | + return false; | ||
292 | + } | ||
293 | + | ||
294 | + public boolean isConnected(Wiimote wiimote) { | ||
295 | + return wiimote != null && wiimote.getWiiRemote().isConnected(); | ||
296 | + } | ||
297 | + | ||
298 | + public int getNumberOfConnectedWiimotes() { | ||
299 | + return remotes.size(); | ||
300 | + } | ||
301 | + | ||
302 | + public Collection<Wiimote> getConnectedWiimotes() { | ||
303 | + return remotes.values(); | ||
304 | + } | ||
305 | + | ||
306 | + public boolean isCursorControl() { | ||
307 | + return cursorControl; | ||
308 | + } | ||
309 | + | ||
310 | + public void setCursorControl(boolean cursorControl) { | ||
311 | + this.cursorControl = cursorControl; | ||
312 | + } | ||
313 | + | ||
314 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteDataHandler.java~
0 → 100644
@@ -0,0 +1,339 @@ | @@ -0,0 +1,339 @@ | ||
1 | +package org.mote.wiimote.whiteboard; | ||
2 | + | ||
3 | +import java.awt.Point; | ||
4 | +import java.util.Collection; | ||
5 | +import java.util.Collections; | ||
6 | +import java.util.EventObject; | ||
7 | +import java.util.HashSet; | ||
8 | +import java.util.LinkedHashMap; | ||
9 | +import java.util.Map; | ||
10 | +import java.util.Set; | ||
11 | +import java.util.logging.Level; | ||
12 | + | ||
13 | +import org.jdesktop.application.Application; | ||
14 | +import org.jdesktop.application.Application.ExitListener; | ||
15 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
16 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
17 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
18 | +import org.mote.wiimote.whiteboard.mouse.CursorControlStrategy; | ||
19 | +import org.mote.wiimote.whiteboard.mouse.Mouse; | ||
20 | +import org.mote.wiimote.whiteboard.mouse.smoothing.MouseSmoothingStrategy; | ||
21 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
22 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences.PreferencesListener; | ||
23 | + | ||
24 | +import wiiremotej.WiiRemote; | ||
25 | +import wiiremotej.WiiRemoteJ; | ||
26 | +import wiiremotej.event.WRButtonEvent; | ||
27 | +import wiiremotej.event.WRIREvent; | ||
28 | +import wiiremotej.event.WRStatusEvent; | ||
29 | +import wiiremotej.event.WiiDeviceDiscoveredEvent; | ||
30 | +import wiiremotej.event.WiiDeviceDiscoveryListener; | ||
31 | +import wiiremotej.event.WiiRemoteAdapter; | ||
32 | + | ||
33 | +public class WiimoteDataHandler extends WiiRemoteAdapter implements ExitListener, WiiDeviceDiscoveryListener, PreferencesListener { | ||
34 | + | ||
35 | + public static interface WiimoteDataListener { | ||
36 | + public void wiimoteConnected(Wiimote wiimote); | ||
37 | + public void wiimoteDisconnected(Wiimote wiimote); | ||
38 | + public void irLights(Wiimote wiimote, IRDot[] lights); | ||
39 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped); | ||
40 | + public void batteryLevel(Wiimote wiimote, double level); | ||
41 | + } | ||
42 | + | ||
43 | + private Map<WiiRemote, Wiimote> remotes = new LinkedHashMap<WiiRemote, Wiimote>(WWPreferences.WIIMOTES, 1f); | ||
44 | + private Map<WiiRemote, WRIREvent> events = new LinkedHashMap<WiiRemote, WRIREvent>(WWPreferences.WIIMOTES, 1f); | ||
45 | + private final WiimoteCalibration calibration; | ||
46 | + private static final WWPreferences prefs = WWPreferences.getPreferences(); | ||
47 | + private final Set<WiimoteDataListener> listener = Collections.synchronizedSet(new HashSet<WiimoteDataListener>()); | ||
48 | + | ||
49 | + private boolean cursorControl = true; | ||
50 | + | ||
51 | + private MouseSmoothingStrategy mss[] = new MouseSmoothingStrategy[4]; | ||
52 | + private CursorControlStrategy cursorControlStrategy; | ||
53 | + | ||
54 | + public WiimoteDataHandler(WiimoteCalibration calibration) { | ||
55 | + this.calibration = calibration; | ||
56 | + Application.getInstance().addExitListener(this); | ||
57 | + prefs.addPreferencesListener(this); | ||
58 | + preferencesChanged(); | ||
59 | + new WiimoteConnector(this).connect(); | ||
60 | + } | ||
61 | + | ||
62 | + public void enableIR(Wiimote wiimote) throws Exception { | ||
63 | + if (wiimote != null && wiimote.getWiiRemote().isConnected()) { | ||
64 | + wiimote.getWiiRemote().setIRSensorEnabled(true, WRIREvent.BASIC, WWPreferences.SENSITIVITY_SETTINGS); | ||
65 | + } | ||
66 | + WiimoteWhiteboard.getLogger().info(String.format("(Re-)Setting IR sensor of Wiimote %d: %s", wiimote.getId(), (wiimote != null && wiimote.getWiiRemote().isConnected() ? "done" : "not connected"))); | ||
67 | + } | ||
68 | + | ||
69 | + void addRemote(final WiiRemote remote) { | ||
70 | + try { | ||
71 | + int id = remotes.size()+1; | ||
72 | + final Wiimote wiimote = new Wiimote(remote, remote.getBluetoothAddress(), id); | ||
73 | + remotes.put(remote, wiimote); | ||
74 | + remote.setAccelerometerEnabled(false); | ||
75 | + enableIR(wiimote); | ||
76 | + remote.setLEDIlluminated(id-1, true); | ||
77 | + remote.setUseMouse(false); | ||
78 | + | ||
79 | + synchronized (listener) { | ||
80 | + for (WiimoteDataListener l : listener) | ||
81 | + l.wiimoteConnected(wiimote); | ||
82 | + } | ||
83 | + | ||
84 | + } catch (Exception e) { | ||
85 | + e.printStackTrace(); | ||
86 | + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Error on configuring Wii Remote", e); | ||
87 | + } | ||
88 | + | ||
89 | + remote.addWiiRemoteListener(this); | ||
90 | + | ||
91 | + // update battery level every minute | ||
92 | + new Thread(new Runnable() { | ||
93 | + public void run() { | ||
94 | + while (true) { | ||
95 | + try { | ||
96 | + // triggers #statusReported(WRStatusEvent) | ||
97 | + if (remote.isConnected()) | ||
98 | + remote.requestStatus(); | ||
99 | + } catch (Exception e) { | ||
100 | + e.printStackTrace(); | ||
101 | + WiimoteWhiteboard.getLogger().log(Level.WARNING, "Error on requesting status from Wii Remote", e); | ||
102 | + } | ||
103 | + try { | ||
104 | + Thread.sleep(60 * 1000); | ||
105 | + } catch (InterruptedException e) { | ||
106 | + e.printStackTrace(); | ||
107 | + } | ||
108 | + } | ||
109 | + } | ||
110 | + }).start(); | ||
111 | + } | ||
112 | + | ||
113 | + | ||
114 | + /* | ||
115 | + * EXIT | ||
116 | + */ | ||
117 | + | ||
118 | + public void willExit(EventObject event) { | ||
119 | + for (WiiRemote remote : remotes.keySet()) | ||
120 | + remote.disconnect(); | ||
121 | + } | ||
122 | + | ||
123 | + public boolean canExit(EventObject event) { | ||
124 | + return true; | ||
125 | + } | ||
126 | + | ||
127 | + | ||
128 | + /* | ||
129 | + * WIIREMOTEJ LISTENER | ||
130 | + */ | ||
131 | + | ||
132 | + @Override | ||
133 | + public synchronized void IRInputReceived(WRIREvent e) { | ||
134 | + events.put(e.getSource(), e); | ||
135 | + // wait till data from all connected wiimotes was received once and only process input on data from first wiimote to reduce the number of times the function gets called | ||
136 | + if (events.size() == getNumberOfConnectedWiimotes() && remotes.get(e.getSource()).getId() == 1) | ||
137 | + IRInputReceived(); | ||
138 | + } | ||
139 | + | ||
140 | + private void IRInputReceived() { | ||
141 | + boolean firstDotVisible = false; | ||
142 | + Map<Wiimote, IRDot[]> data = new LinkedHashMap<Wiimote, IRDot[]>(); | ||
143 | + for (WiiRemote r : events.keySet()) { | ||
144 | + Wiimote wiimote = remotes.get(r); | ||
145 | + IRDot[] dots = IRDot.getIRDots(events.get(r).getIRLights()); | ||
146 | + | ||
147 | + synchronized (listener) { | ||
148 | + for (WiimoteDataListener l : listener) | ||
149 | + l.irLights(wiimote, dots); | ||
150 | + } | ||
151 | + | ||
152 | + // exclude points from uncalibrated wiimotes during "normal operation" | ||
153 | + if (!calibration.isDone() || calibration.isCalibrated(wiimote)) { | ||
154 | + firstDotVisible = firstDotVisible || dots[0] != null; | ||
155 | + data.put(wiimote, dots); | ||
156 | + } | ||
157 | + } | ||
158 | + | ||
159 | + if (calibration.isDone()) { | ||
160 | + // should always be true, but just in case... | ||
161 | + if (calibration.isAnyCalibrated(data.keySet())) { | ||
162 | + Point warped[] = calibration.warp(data); | ||
163 | + for (int i = 0; i < 4; i++) { | ||
164 | + if (warped[i] != null) { | ||
165 | + warped[i] = mss[i].translate(warped[i]); | ||
166 | + } else { | ||
167 | + mss[i].reset(); | ||
168 | + } | ||
169 | + } | ||
170 | + | ||
171 | + if (isCursorControl()) { | ||
172 | + cursorControlStrategy.process(warped[0]); | ||
173 | + } else { | ||
174 | +// if (Mouse.LEFT_BUTTON.isPressed()) | ||
175 | + Mouse.LEFT_BUTTON.setPressed(false); | ||
176 | +// if (Mouse.RIGHT_BUTTON.isPressed()) | ||
177 | + Mouse.RIGHT_BUTTON.setPressed(false); | ||
178 | + } | ||
179 | + | ||
180 | +// if (warped[0] != null) { | ||
181 | +// // normal operation after calibration has been done | ||
182 | +// if (isCursorControl()) { | ||
183 | +// Mouse.move(warped[0]); | ||
184 | +// rcs.process(warped[0]); | ||
185 | +// if (prefs.isLeftClick() && !(prefs.isRightClick() && rcs.trigger())) { | ||
186 | +// Mouse.LEFT_BUTTON.setPressed(true); | ||
187 | +// } | ||
188 | +// } | ||
189 | +// } else { | ||
190 | +// rcs.process(null); | ||
191 | +// Mouse.LEFT_BUTTON.setPressed(false); | ||
192 | +// } | ||
193 | + | ||
194 | + synchronized (listener) { | ||
195 | + for (WiimoteDataListener l : listener) | ||
196 | + l.irWarped(data, warped); | ||
197 | + } | ||
198 | + | ||
199 | + } | ||
200 | + } else if (calibration.inProgress()) { | ||
201 | + if (firstDotVisible) | ||
202 | + calibration.process(data); | ||
203 | + } | ||
204 | + | ||
205 | + } | ||
206 | + | ||
207 | + @Override | ||
208 | + public void statusReported(WRStatusEvent e) { | ||
209 | + synchronized (listener) { | ||
210 | + for (WiimoteDataListener l : listener) | ||
211 | + l.batteryLevel(remotes.get(e.getSource()), e.getBatteryLevel()); | ||
212 | + } | ||
213 | + } | ||
214 | + | ||
215 | + @Override | ||
216 | + public void buttonInputReceived(WRButtonEvent e) { | ||
217 | + if (e.isOnlyPressed(WRButtonEvent.A)) { | ||
218 | + calibration.start(getConnectedWiimotes()); | ||
219 | + } else if (e.isOnlyPressed(WRButtonEvent.HOME)) { | ||
220 | + Application.getInstance().exit(); | ||
221 | + } | ||
222 | + } | ||
223 | + | ||
224 | + public void wiiDeviceDiscovered(WiiDeviceDiscoveredEvent e) { | ||
225 | + if (e.getWiiDevice() instanceof WiiRemote) { | ||
226 | + addRemote((WiiRemote)e.getWiiDevice()); | ||
227 | + } | ||
228 | + } | ||
229 | + | ||
230 | + public void findFinished(int numberFound) { | ||
231 | + } | ||
232 | + | ||
233 | + @Override | ||
234 | + public void disconnected() { | ||
235 | + // TODO support dis-/reconnecting? | ||
236 | + WiiRemoteJ.stopFind(); | ||
237 | + WiiRemote remove = null; | ||
238 | + for (WiiRemote remote : remotes.keySet()) { | ||
239 | + if (!remote.isConnected()) { | ||
240 | + remove = remote; | ||
241 | + synchronized (listener) { | ||
242 | + for (WiimoteDataListener l : listener) | ||
243 | + l.wiimoteDisconnected(remotes.get(remote)); | ||
244 | + } | ||
245 | + break; | ||
246 | + } | ||
247 | + } | ||
248 | + if (remove != null) remotes.remove(remove); | ||
249 | + } | ||
250 | + | ||
251 | + | ||
252 | + /* | ||
253 | + * LISTENER | ||
254 | + */ | ||
255 | + | ||
256 | + public void addWiimoteDataListener(WiimoteDataListener l) { | ||
257 | + listener.add(l); | ||
258 | + } | ||
259 | + | ||
260 | + public void removeWiimoteDataListener(WiimoteDataListener l) { | ||
261 | + listener.remove(l); | ||
262 | + } | ||
263 | + | ||
264 | + /* | ||
265 | + * PREFERENCES STUFF | ||
266 | + */ | ||
267 | + | ||
268 | + public void preferencesChanged() { | ||
269 | + updateMSS(); | ||
270 | + updateCursorControlStrategy(); | ||
271 | +// final int newNumWiimotes = prefs.getNumberOfWiimotes(); | ||
272 | +// if (numWiimotes != newNumWiimotes) { | ||
273 | +// WiiRemoteJ.stopFind(); | ||
274 | +// if (newNumWiimotes > getNumberOfConnectedWiimotes()) { | ||
275 | +// WiiRemoteJ.findRemotes(this, newNumWiimotes - getNumberOfConnectedWiimotes()); | ||
276 | +// } | ||
277 | +// numWiimotes = newNumWiimotes; | ||
278 | +// } | ||
279 | + } | ||
280 | + | ||
281 | + @SuppressWarnings("unchecked") | ||
282 | + private void updateCursorControlStrategy() { | ||
283 | + if (cursorControlStrategy == null || !cursorControlStrategy.getClass().getName().equals(prefs.getCursorControl())) { | ||
284 | + try { | ||
285 | + Class<?> c = Class.forName(prefs.getCursorControl()); | ||
286 | + cursorControlStrategy = ((Class<? extends CursorControlStrategy>)c).newInstance(); | ||
287 | + } catch (Exception e) { | ||
288 | + e.printStackTrace(); | ||
289 | + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Cursor Control Method error.", e); | ||
290 | + } | ||
291 | + } | ||
292 | + } | ||
293 | + | ||
294 | + @SuppressWarnings("unchecked") | ||
295 | + private void updateMSS() { | ||
296 | + if (mss[0] == null || !mss[0].getClass().getName().equals(prefs.getMouseSmoothing())) { | ||
297 | + try { | ||
298 | + Class<?> c = Class.forName(prefs.getMouseSmoothing()); | ||
299 | + for (int i = 0; i < 4; i++) | ||
300 | + mss[i] = ((Class<? extends MouseSmoothingStrategy>)c).newInstance(); | ||
301 | + } catch (Exception e) { | ||
302 | + e.printStackTrace(); | ||
303 | + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Mouse Movement Smoothing error.", e); | ||
304 | + } | ||
305 | + } | ||
306 | + } | ||
307 | + | ||
308 | + /* | ||
309 | + * GETTER & SETTER | ||
310 | + */ | ||
311 | + | ||
312 | + public boolean isConnected() { | ||
313 | + for (WiiRemote remote : remotes.keySet()) { | ||
314 | + if (remote.isConnected()) return true; | ||
315 | + } | ||
316 | + return false; | ||
317 | + } | ||
318 | + | ||
319 | + public boolean isConnected(Wiimote wiimote) { | ||
320 | + return wiimote != null && wiimote.getWiiRemote().isConnected(); | ||
321 | + } | ||
322 | + | ||
323 | + public int getNumberOfConnectedWiimotes() { | ||
324 | + return remotes.size(); | ||
325 | + } | ||
326 | + | ||
327 | + public Collection<Wiimote> getConnectedWiimotes() { | ||
328 | + return remotes.values(); | ||
329 | + } | ||
330 | + | ||
331 | + public boolean isCursorControl() { | ||
332 | + return cursorControl; | ||
333 | + } | ||
334 | + | ||
335 | + public void setCursorControl(boolean cursorControl) { | ||
336 | + this.cursorControl = cursorControl; | ||
337 | + } | ||
338 | + | ||
339 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteWhiteboard.java
0 → 100644
@@ -0,0 +1,153 @@ | @@ -0,0 +1,153 @@ | ||
1 | +package org.mote.wiimote.whiteboard; | ||
2 | + | ||
3 | +import java.util.Locale; | ||
4 | +import java.util.logging.Level; | ||
5 | +import java.util.logging.Logger; | ||
6 | + | ||
7 | +import javax.swing.JFrame; | ||
8 | +import javax.swing.JOptionPane; | ||
9 | + | ||
10 | +import org.jdesktop.application.Action; | ||
11 | +import org.jdesktop.application.Application; | ||
12 | +import org.jdesktop.application.SingleFrameApplication; | ||
13 | +import org.mote.wiimote.whiteboard.calibration.CalibrationPersistence; | ||
14 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
15 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
16 | +import org.mote.wiimote.whiteboard.gui.AboutWindow; | ||
17 | +import org.mote.wiimote.whiteboard.gui.HelpHandler; | ||
18 | +import org.mote.wiimote.whiteboard.gui.LogWindow; | ||
19 | +import org.mote.wiimote.whiteboard.gui.MainPanel; | ||
20 | +import org.mote.wiimote.whiteboard.gui.MenuBar; | ||
21 | +import org.mote.wiimote.whiteboard.gui.PreferencesWindow; | ||
22 | +import org.mote.wiimote.whiteboard.mouse.Mouse; | ||
23 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
24 | +import org.mote.wiimote.whiteboard.tuio.TuioTransmitter; | ||
25 | +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch; | ||
26 | +import org.mote.wiimote.whiteboard.util.UpdateNotifier; | ||
27 | +import org.mote.wiimote.whiteboard.util.Util; | ||
28 | +import org.mote.wiimote.whiteboard.util.WiiRemoteJErrorHandler; | ||
29 | + | ||
30 | +import wiiremotej.WiiRemoteJ; | ||
31 | +import apple.dts.samplecode.osxadapter.OSXAdapter; | ||
32 | + | ||
33 | +public class WiimoteWhiteboard extends SingleFrameApplication { | ||
34 | + | ||
35 | + public static void main(String args[]) { | ||
36 | + if (Util.MAC_OS_X && !Util.INSIDE_APP_BUNDLE) { | ||
37 | + System.setProperty("apple.laf.useScreenMenuBar", "true"); | ||
38 | + System.setProperty("com.apple.mrj.application.apple.menu.about.name", getProperty("id")); | ||
39 | + } | ||
40 | + System.setProperty("bluecove.jsr82.psm_minimum_off", "true"); | ||
41 | + | ||
42 | + String lang = WWPreferences.getPreferences().getLanguage(); | ||
43 | + if (lang.length() > 0) { | ||
44 | + String[] langParts = lang.split("_"); | ||
45 | + switch (langParts.length) { | ||
46 | + case 1: | ||
47 | + Locale.setDefault(new Locale(langParts[0])); | ||
48 | + break; | ||
49 | + case 2: | ||
50 | + Locale.setDefault(new Locale(langParts[0], langParts[1])); | ||
51 | + break; | ||
52 | + } | ||
53 | + } | ||
54 | + Application.launch(WiimoteWhiteboard.class, args); | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + protected void startup() { | ||
59 | + try { | ||
60 | + new Thread(new Runnable() { | ||
61 | + public void run() { | ||
62 | + // blocking | ||
63 | + if (WWPreferences.getPreferences().checkForUpdates()) | ||
64 | + UpdateNotifier.checkForUpdate(getProperty("version")); | ||
65 | + } | ||
66 | + }).start(); | ||
67 | + | ||
68 | + Logger.getLogger("wiimotewhiteboard").setUseParentHandlers(false); | ||
69 | + | ||
70 | + final JFrame f = getMainFrame(); | ||
71 | + LogWindow lw = new LogWindow(); | ||
72 | + | ||
73 | + final WiimoteCalibration calibration = new WiimoteCalibration(); | ||
74 | + WiimoteDataHandler dh = new WiimoteDataHandler(calibration); | ||
75 | + | ||
76 | +// new IRDotLogger(dh); | ||
77 | + | ||
78 | + MainPanel mp = new MainPanel(dh, calibration); | ||
79 | + AboutWindow af = new AboutWindow(); | ||
80 | + HelpHandler hh = new HelpHandler(); | ||
81 | + PreferencesWindow pf = new PreferencesWindow(mp, hh); | ||
82 | + f.setJMenuBar(new MenuBar(pf, af, hh, lw)); | ||
83 | + registerForMacOSXEvents(pf, af); | ||
84 | + | ||
85 | + // update Mouse's screen | ||
86 | + calibration.addCalibrationEventListener(new WiimoteCalibration.CalibrationEventListener() { | ||
87 | + public void calibrationEvent(CalibrationEvent e) { | ||
88 | + if (e == CalibrationEvent.SCREEN_CHANGED) | ||
89 | + Mouse.setScreen(calibration.getScreen()); | ||
90 | + } | ||
91 | + }); | ||
92 | + | ||
93 | + new CalibrationPersistence(calibration); | ||
94 | + calibration.setScreen(WiimoteCalibration.DEFAULT_SCREEN); | ||
95 | + | ||
96 | + new TuioTransmitter(dh, calibration); | ||
97 | + | ||
98 | + WiiRemoteJ.setConsoleLoggingErrors(); | ||
99 | + Logger.getLogger("wiiremotej").setLevel(Level.ALL); | ||
100 | + Logger.getLogger("wiiremotej").addHandler(new WiiRemoteJErrorHandler(dh)); | ||
101 | + | ||
102 | + try { | ||
103 | + getContext().getSessionStorage().restore(f, "mainFrame.session.xml"); | ||
104 | + } catch (Exception e) {} | ||
105 | + | ||
106 | + show(mp); | ||
107 | + f.pack(); | ||
108 | + | ||
109 | + } catch (Exception e) { | ||
110 | + e.printStackTrace(); | ||
111 | + getLogger().log(Level.SEVERE, "Error on startup", e); | ||
112 | + JOptionPane.showMessageDialog(null, e.getMessage(), getProperty("id"), JOptionPane.ERROR_MESSAGE); | ||
113 | + exit(); | ||
114 | + } | ||
115 | + } | ||
116 | + | ||
117 | + /* | ||
118 | + * MAC OS X HOOKS | ||
119 | + */ | ||
120 | + private void registerForMacOSXEvents(PreferencesWindow pf, AboutWindow af) { | ||
121 | + if (Util.MAC_OS_X) { | ||
122 | + try { | ||
123 | + OSXAdapter.setQuitHandler(this, WiimoteWhiteboard.class.getDeclaredMethod("quitApp", (Class[])null)); | ||
124 | + if (!Util.INSIDE_APP_BUNDLE) { | ||
125 | + OSXAdapter.setAboutHandler(af, AboutWindow.class.getDeclaredMethod("about", (Class[])null)); | ||
126 | + } | ||
127 | + OSXAdapter.setPreferencesHandler(pf, PreferencesWindow.class.getDeclaredMethod("preferences", (Class[])null)); | ||
128 | + } catch (Exception e) { | ||
129 | + e.printStackTrace(); | ||
130 | + } | ||
131 | + } | ||
132 | + } | ||
133 | + | ||
134 | + @Action | ||
135 | + public boolean quitApp() { | ||
136 | + exit(); | ||
137 | + return false; | ||
138 | + } | ||
139 | + | ||
140 | + @Action | ||
141 | + public void donate() { | ||
142 | + BareBonesBrowserLaunch.openURL(getProperty("donateURL")); | ||
143 | + } | ||
144 | + | ||
145 | + public static String getProperty(String key) { | ||
146 | + return Util.getResourceMap(WiimoteWhiteboard.class).getString("Application."+key); | ||
147 | + } | ||
148 | + | ||
149 | + public static Logger getLogger() { | ||
150 | + return Logger.getLogger("wiimotewhiteboard"); | ||
151 | + } | ||
152 | + | ||
153 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteWhiteboard.java~
0 → 100644
@@ -0,0 +1,159 @@ | @@ -0,0 +1,159 @@ | ||
1 | +package org.mote.wiimote.whiteboard; | ||
2 | + | ||
3 | +import java.util.Locale; | ||
4 | +import java.util.logging.Level; | ||
5 | +import java.util.logging.Logger; | ||
6 | + | ||
7 | +import javax.swing.JFrame; | ||
8 | +import javax.swing.JOptionPane; | ||
9 | + | ||
10 | +import org.jdesktop.application.Action; | ||
11 | +import org.jdesktop.application.Application; | ||
12 | +import org.jdesktop.application.SingleFrameApplication; | ||
13 | +import org.mote.wiimote.whiteboard.calibration.CalibrationPersistence; | ||
14 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
15 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
16 | +import org.mote.wiimote.whiteboard.gui.AboutWindow; | ||
17 | +import org.mote.wiimote.whiteboard.gui.HelpHandler; | ||
18 | +import org.mote.wiimote.whiteboard.gui.LogWindow; | ||
19 | +import org.mote.wiimote.whiteboard.gui.MainPanel; | ||
20 | +import org.mote.wiimote.whiteboard.gui.MenuBar; | ||
21 | +import org.mote.wiimote.whiteboard.gui.PreferencesWindow; | ||
22 | +import org.mote.wiimote.whiteboard.mouse.Mouse; | ||
23 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
24 | +import org.mote.wiimote.whiteboard.tuio.TuioTransmitter; | ||
25 | +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch; | ||
26 | +import org.mote.wiimote.whiteboard.util.UpdateNotifier; | ||
27 | +import org.mote.wiimote.whiteboard.util.Util; | ||
28 | +import org.mote.wiimote.whiteboard.util.WiiRemoteJErrorHandler; | ||
29 | + | ||
30 | +import wiiremotej.WiiRemoteJ; | ||
31 | +import apple.dts.samplecode.osxadapter.OSXAdapter; | ||
32 | + | ||
33 | +public class WiimoteWhiteboard extends SingleFrameApplication { | ||
34 | + | ||
35 | + public static void main(String args[]) { | ||
36 | + if (Util.MAC_OS_X && !Util.INSIDE_APP_BUNDLE) { | ||
37 | + System.setProperty("apple.laf.useScreenMenuBar", "true"); | ||
38 | + System.setProperty("com.apple.mrj.application.apple.menu.about.name", getProperty("id")); | ||
39 | + } | ||
40 | + System.setProperty("bluecove.jsr82.psm_minimum_off", "true"); | ||
41 | + | ||
42 | + String lang = WWPreferences.getPreferences().getLanguage(); | ||
43 | + if (lang.length() > 0) { | ||
44 | + String[] langParts = lang.split("_"); | ||
45 | + switch (langParts.length) { | ||
46 | + case 1: | ||
47 | + Locale.setDefault(new Locale(langParts[0])); | ||
48 | + break; | ||
49 | + case 2: | ||
50 | + Locale.setDefault(new Locale(langParts[0], langParts[1])); | ||
51 | + break; | ||
52 | + } | ||
53 | + } | ||
54 | + Application.launch(WiimoteWhiteboard.class, args); | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + protected void startup() { | ||
59 | + try { | ||
60 | + new Thread(new Runnable() { | ||
61 | + public void run() { | ||
62 | + // blocking | ||
63 | + if (WWPreferences.getPreferences().checkForUpdates()) | ||
64 | + UpdateNotifier.checkForUpdate(getProperty("version")); | ||
65 | + } | ||
66 | + }).start(); | ||
67 | + | ||
68 | + Logger.getLogger("wiimotewhiteboard").setUseParentHandlers(false); | ||
69 | + | ||
70 | + final JFrame f = getMainFrame(); | ||
71 | + LogWindow lw = new LogWindow(); | ||
72 | + | ||
73 | + final WiimoteCalibration calibration = new WiimoteCalibration(); | ||
74 | + WiimoteDataHandler dh = new WiimoteDataHandler(calibration); | ||
75 | + | ||
76 | +// new IRDotLogger(dh); | ||
77 | + | ||
78 | + MainPanel mp = new MainPanel(dh, calibration); | ||
79 | + AboutWindow af = new AboutWindow(); | ||
80 | + HelpHandler hh = new HelpHandler(); | ||
81 | + PreferencesWindow pf = new PreferencesWindow(mp, hh); | ||
82 | + f.setJMenuBar(new MenuBar(pf, af, hh, lw)); | ||
83 | + registerForMacOSXEvents(pf, af); | ||
84 | + | ||
85 | + // update Mouse's screen | ||
86 | + calibration.addCalibrationEventListener(new WiimoteCalibration.CalibrationEventListener() { | ||
87 | + public void calibrationEvent(CalibrationEvent e) { | ||
88 | + if (e == CalibrationEvent.SCREEN_CHANGED) | ||
89 | + Mouse.setScreen(calibration.getScreen()); | ||
90 | + } | ||
91 | + }); | ||
92 | + | ||
93 | + // add persistence as last listener because it indirectly generates new calibration events | ||
94 | + new CalibrationPersistence(calibration); | ||
95 | + // TODO save last used screen? | ||
96 | + calibration.setScreen(WiimoteCalibration.DEFAULT_SCREEN); | ||
97 | + | ||
98 | + new TuioTransmitter(dh, calibration); | ||
99 | + | ||
100 | + WiiRemoteJ.setConsoleLoggingErrors(); | ||
101 | + Logger.getLogger("wiiremotej").setLevel(Level.ALL); | ||
102 | + Logger.getLogger("wiiremotej").addHandler(new WiiRemoteJErrorHandler(dh)); | ||
103 | + | ||
104 | + try { | ||
105 | + // restore session manually before 'show' on the main panel is | ||
106 | + // called. this is a fix to the problem that the session is not | ||
107 | + // restored; apparently because mainFrame is not resizable | ||
108 | + getContext().getSessionStorage().restore(f, "mainFrame.session.xml"); | ||
109 | + } catch (Exception e) {} | ||
110 | + | ||
111 | + show(mp); | ||
112 | + // f.pack() is called in 'show' above if f.isValid() == false | ||
113 | + f.pack(); | ||
114 | + | ||
115 | + } catch (Exception e) { | ||
116 | + e.printStackTrace(); | ||
117 | + getLogger().log(Level.SEVERE, "Error on startup", e); | ||
118 | + JOptionPane.showMessageDialog(null, e.getMessage(), getProperty("id"), JOptionPane.ERROR_MESSAGE); | ||
119 | + exit(); | ||
120 | + } | ||
121 | + } | ||
122 | + | ||
123 | + /* | ||
124 | + * MAC OS X HOOKS | ||
125 | + */ | ||
126 | + private void registerForMacOSXEvents(PreferencesWindow pf, AboutWindow af) { | ||
127 | + if (Util.MAC_OS_X) { | ||
128 | + try { | ||
129 | + OSXAdapter.setQuitHandler(this, WiimoteWhiteboard.class.getDeclaredMethod("quitApp", (Class[])null)); | ||
130 | + if (!Util.INSIDE_APP_BUNDLE) { | ||
131 | + OSXAdapter.setAboutHandler(af, AboutWindow.class.getDeclaredMethod("about", (Class[])null)); | ||
132 | + } | ||
133 | + OSXAdapter.setPreferencesHandler(pf, PreferencesWindow.class.getDeclaredMethod("preferences", (Class[])null)); | ||
134 | + } catch (Exception e) { | ||
135 | + e.printStackTrace(); | ||
136 | + } | ||
137 | + } | ||
138 | + } | ||
139 | + | ||
140 | + @Action | ||
141 | + public boolean quitApp() { | ||
142 | + exit(); | ||
143 | + return false; | ||
144 | + } | ||
145 | + | ||
146 | + @Action | ||
147 | + public void donate() { | ||
148 | + BareBonesBrowserLaunch.openURL(getProperty("donateURL")); | ||
149 | + } | ||
150 | + | ||
151 | + public static String getProperty(String key) { | ||
152 | + return Util.getResourceMap(WiimoteWhiteboard.class).getString("Application."+key); | ||
153 | + } | ||
154 | + | ||
155 | + public static Logger getLogger() { | ||
156 | + return Logger.getLogger("wiimotewhiteboard"); | ||
157 | + } | ||
158 | + | ||
159 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/CalibrationPersistence.java
0 → 100644
@@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
1 | +package org.mote.wiimote.whiteboard.calibration; | ||
2 | + | ||
3 | +import java.awt.DisplayMode; | ||
4 | +import java.io.IOException; | ||
5 | + | ||
6 | +import org.jdesktop.application.Application; | ||
7 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
8 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener; | ||
9 | + | ||
10 | +public class CalibrationPersistence implements CalibrationEventListener { | ||
11 | + | ||
12 | + WiimoteCalibration calibration; | ||
13 | + | ||
14 | + public CalibrationPersistence(WiimoteCalibration calibration) { | ||
15 | + this.calibration = calibration; | ||
16 | + calibration.addCalibrationEventListener(this); | ||
17 | + } | ||
18 | + | ||
19 | + public void calibrationEvent(CalibrationEvent e) { | ||
20 | + switch (e) { | ||
21 | + case SCREEN_CHANGED: | ||
22 | + loadCalibrationData(); | ||
23 | + break; | ||
24 | + case FINISHED: | ||
25 | + saveCalibrationData(); | ||
26 | + break; | ||
27 | + } | ||
28 | + } | ||
29 | + | ||
30 | + private String calibrationFileName() { | ||
31 | + DisplayMode dm = calibration.getScreen().getDisplayMode(); | ||
32 | + return String.format("calibration_%d_%dx%d.txt", calibration.getScreenNumber(), dm.getWidth(), dm.getHeight()); | ||
33 | + } | ||
34 | + | ||
35 | + private void loadCalibrationData() { | ||
36 | + try { | ||
37 | + String fileName = calibrationFileName(); | ||
38 | + calibration.load(Application.getInstance().getContext().getLocalStorage().openInputFile(fileName)); | ||
39 | + } catch (IOException e) { | ||
40 | + // ignore | ||
41 | + } | ||
42 | + } | ||
43 | + | ||
44 | + private void saveCalibrationData() { | ||
45 | + try { | ||
46 | + String fileName = calibrationFileName(); | ||
47 | + calibration.save(Application.getInstance().getContext().getLocalStorage().openOutputFile(fileName)); | ||
48 | + } catch (IOException e) { | ||
49 | + // ignore | ||
50 | + } | ||
51 | + } | ||
52 | + | ||
53 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/CalibrationPersistence.java~
0 → 100644
@@ -0,0 +1,82 @@ | @@ -0,0 +1,82 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.calibration; | ||
27 | + | ||
28 | +import java.awt.DisplayMode; | ||
29 | +import java.io.IOException; | ||
30 | + | ||
31 | +import org.jdesktop.application.Application; | ||
32 | +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
33 | +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener; | ||
34 | + | ||
35 | +public class CalibrationPersistence implements CalibrationEventListener { | ||
36 | + | ||
37 | + WiimoteCalibration calibration; | ||
38 | + | ||
39 | + public CalibrationPersistence(WiimoteCalibration calibration) { | ||
40 | + this.calibration = calibration; | ||
41 | + calibration.addCalibrationEventListener(this); | ||
42 | + } | ||
43 | + | ||
44 | + public void calibrationEvent(CalibrationEvent e) { | ||
45 | + switch (e) { | ||
46 | + case SCREEN_CHANGED: | ||
47 | + loadCalibrationData(); | ||
48 | + break; | ||
49 | + case FINISHED: | ||
50 | + saveCalibrationData(); | ||
51 | + break; | ||
52 | + } | ||
53 | + } | ||
54 | + | ||
55 | +// private String safeFilename(String rawName) { | ||
56 | +// return rawName.replaceAll("[\\W]", "").toLowerCase(); | ||
57 | +// } | ||
58 | + | ||
59 | + private String calibrationFileName() { | ||
60 | + DisplayMode dm = calibration.getScreen().getDisplayMode(); | ||
61 | + return String.format("calibration_%d_%dx%d.txt", calibration.getScreenNumber(), dm.getWidth(), dm.getHeight()); | ||
62 | + } | ||
63 | + | ||
64 | + private void loadCalibrationData() { | ||
65 | + try { | ||
66 | + String fileName = calibrationFileName(); | ||
67 | + calibration.load(Application.getInstance().getContext().getLocalStorage().openInputFile(fileName)); | ||
68 | + } catch (IOException e) { | ||
69 | + // ignore | ||
70 | + } | ||
71 | + } | ||
72 | + | ||
73 | + private void saveCalibrationData() { | ||
74 | + try { | ||
75 | + String fileName = calibrationFileName(); | ||
76 | + calibration.save(Application.getInstance().getContext().getLocalStorage().openOutputFile(fileName)); | ||
77 | + } catch (IOException e) { | ||
78 | + // ignore | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/PointClusterer.java
0 → 100644
@@ -0,0 +1,72 @@ | @@ -0,0 +1,72 @@ | ||
1 | +package org.mote.wiimote.whiteboard.calibration; | ||
2 | + | ||
3 | +import java.util.HashSet; | ||
4 | +import java.util.Map; | ||
5 | +import java.util.Set; | ||
6 | + | ||
7 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
8 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
9 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
10 | + | ||
11 | +public class PointClusterer { | ||
12 | + | ||
13 | + static { | ||
14 | + if (WWPreferences.WIIMOTES > 2) | ||
15 | + throw new RuntimeException("Clustering for more than 2 Wiimotes not implemented yet."); | ||
16 | + } | ||
17 | + | ||
18 | + public static IRDot[][] cluster(Map<Wiimote, IRDot[]> data) { | ||
19 | + IRDot[][] cluster = new IRDot[4][]; | ||
20 | + | ||
21 | + if (data.size() == 1) { | ||
22 | + IRDot[] values = data.values().iterator().next(); | ||
23 | + int j = 0; | ||
24 | + for (int i = 0; i < 4; i++) | ||
25 | + if (values[i] != null) | ||
26 | + cluster[j++] = new IRDot[] { values[i] }; | ||
27 | + return cluster; | ||
28 | + } | ||
29 | + | ||
30 | + Wiimote[] wiimotes = new Wiimote[data.keySet().size()]; | ||
31 | + data.keySet().toArray(wiimotes); | ||
32 | + | ||
33 | + Set<IRDot> used = new HashSet<IRDot>(); | ||
34 | + int c = 0; | ||
35 | + | ||
36 | + for (int a = 0; a < 2; a++) { | ||
37 | + | ||
38 | + for (int i = 0; i < 4; i++) { | ||
39 | + IRDot dot1 = data.get(wiimotes[a])[i]; | ||
40 | + if (dot1 == null || used.contains(dot1)) | ||
41 | + continue; | ||
42 | + | ||
43 | + IRDot minDot = null; | ||
44 | + double minDist = Double.POSITIVE_INFINITY; | ||
45 | + | ||
46 | + for (int j = 0; j < 4; j++) { | ||
47 | + IRDot dot2 = data.get(wiimotes[(a+1)%2])[j]; | ||
48 | + if (dot2 == null || used.contains(dot2)) | ||
49 | + continue; | ||
50 | + | ||
51 | + double dist = dot1.distance(dot2); | ||
52 | + if (dist < minDist) { | ||
53 | + minDot = dot2; | ||
54 | + minDist = dist; | ||
55 | + } | ||
56 | + } | ||
57 | + | ||
58 | + used.add(dot1); | ||
59 | + if (minDot == null) { | ||
60 | + cluster[c++] = new IRDot[] { dot1 }; | ||
61 | + } else { | ||
62 | + cluster[c++] = new IRDot[] { dot1, minDot }; | ||
63 | + used.add(minDot); | ||
64 | + } | ||
65 | + | ||
66 | + } | ||
67 | + } | ||
68 | + | ||
69 | + return cluster; | ||
70 | + } | ||
71 | + | ||
72 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/PointClusterer.java~
0 → 100644
@@ -0,0 +1,101 @@ | @@ -0,0 +1,101 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.calibration; | ||
27 | + | ||
28 | +import java.util.HashSet; | ||
29 | +import java.util.Map; | ||
30 | +import java.util.Set; | ||
31 | + | ||
32 | +import org.uweschmidt.wiimote.whiteboard.ds.IRDot; | ||
33 | +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote; | ||
34 | +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences; | ||
35 | + | ||
36 | +public class PointClusterer { | ||
37 | + | ||
38 | + static { | ||
39 | + if (WWPreferences.WIIMOTES > 2) | ||
40 | + throw new RuntimeException("Clustering for more than 2 Wiimotes not implemented yet."); | ||
41 | + } | ||
42 | + | ||
43 | + /** | ||
44 | + * @return array of clusters (first index = cluster number, second index = dots in cluster) | ||
45 | + */ | ||
46 | + public static IRDot[][] cluster(Map<Wiimote, IRDot[]> data) { | ||
47 | + IRDot[][] cluster = new IRDot[4][]; | ||
48 | + | ||
49 | + // trivial case | ||
50 | + if (data.size() == 1) { | ||
51 | + IRDot[] values = data.values().iterator().next(); | ||
52 | + int j = 0; | ||
53 | + for (int i = 0; i < 4; i++) | ||
54 | + if (values[i] != null) | ||
55 | + cluster[j++] = new IRDot[] { values[i] }; | ||
56 | + return cluster; | ||
57 | + } | ||
58 | + | ||
59 | + Wiimote[] wiimotes = new Wiimote[data.keySet().size()]; | ||
60 | + data.keySet().toArray(wiimotes); | ||
61 | + | ||
62 | + Set<IRDot> used = new HashSet<IRDot>(); | ||
63 | + int c = 0; | ||
64 | + | ||
65 | + for (int a = 0; a < 2; a++) { | ||
66 | + | ||
67 | + for (int i = 0; i < 4; i++) { | ||
68 | + IRDot dot1 = data.get(wiimotes[a])[i]; | ||
69 | + if (dot1 == null || used.contains(dot1)) | ||
70 | + continue; | ||
71 | + | ||
72 | + IRDot minDot = null; | ||
73 | + double minDist = Double.POSITIVE_INFINITY; | ||
74 | + | ||
75 | + for (int j = 0; j < 4; j++) { | ||
76 | + IRDot dot2 = data.get(wiimotes[(a+1)%2])[j]; | ||
77 | + if (dot2 == null || used.contains(dot2)) | ||
78 | + continue; | ||
79 | + | ||
80 | + double dist = dot1.distance(dot2); | ||
81 | + if (dist < minDist) { | ||
82 | + minDot = dot2; | ||
83 | + minDist = dist; | ||
84 | + } | ||
85 | + } | ||
86 | + | ||
87 | + used.add(dot1); | ||
88 | + if (minDot == null) { | ||
89 | + cluster[c++] = new IRDot[] { dot1 }; | ||
90 | + } else { | ||
91 | + cluster[c++] = new IRDot[] { dot1, minDot }; | ||
92 | + used.add(minDot); | ||
93 | + } | ||
94 | + | ||
95 | + } | ||
96 | + } | ||
97 | + | ||
98 | + return cluster; | ||
99 | + } | ||
100 | + | ||
101 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/WiimoteCalibration.java
0 → 100644
@@ -0,0 +1,511 @@ | @@ -0,0 +1,511 @@ | ||
1 | +package org.mote.wiimote.whiteboard.calibration; | ||
2 | +import java.awt.Color; | ||
3 | +import java.awt.Graphics; | ||
4 | +import java.awt.Graphics2D; | ||
5 | +import java.awt.GraphicsDevice; | ||
6 | +import java.awt.GraphicsEnvironment; | ||
7 | +import java.awt.Image; | ||
8 | +import java.awt.Point; | ||
9 | +import java.awt.Rectangle; | ||
10 | +import java.awt.RenderingHints; | ||
11 | +import java.awt.event.KeyAdapter; | ||
12 | +import java.awt.event.KeyEvent; | ||
13 | +import java.awt.geom.Point2D; | ||
14 | +import java.io.BufferedReader; | ||
15 | +import java.io.IOException; | ||
16 | +import java.io.InputStream; | ||
17 | +import java.io.InputStreamReader; | ||
18 | +import java.io.OutputStream; | ||
19 | +import java.io.PrintStream; | ||
20 | +import java.util.Arrays; | ||
21 | +import java.util.Collection; | ||
22 | +import java.util.HashMap; | ||
23 | +import java.util.HashSet; | ||
24 | +import java.util.LinkedHashMap; | ||
25 | +import java.util.LinkedHashSet; | ||
26 | +import java.util.Locale; | ||
27 | +import java.util.Map; | ||
28 | +import java.util.Set; | ||
29 | + | ||
30 | +import javax.media.jai.PerspectiveTransform; | ||
31 | +import javax.swing.Icon; | ||
32 | +import javax.swing.ImageIcon; | ||
33 | +import javax.swing.JFrame; | ||
34 | +import javax.swing.JLabel; | ||
35 | +import javax.swing.JOptionPane; | ||
36 | +import javax.swing.JPanel; | ||
37 | +import javax.swing.SwingConstants; | ||
38 | + | ||
39 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
40 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
41 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
42 | +import org.mote.wiimote.whiteboard.util.Util; | ||
43 | + | ||
44 | +public class WiimoteCalibration { | ||
45 | + | ||
46 | + // list of all "rectangles" of the 3x3 calibration grid, larger to smaller | ||
47 | + private static final CalibrationState[][] VALID_STATES = { | ||
48 | + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT}, | ||
49 | + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT}, | ||
50 | + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE}, | ||
51 | + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.WEST_MIDDLE}, | ||
52 | + {CalibrationState.WEST_MIDDLE, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT}, | ||
53 | + {CalibrationState.WEST_MIDDLE, CalibrationState.CENTER, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT}, | ||
54 | + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.CENTER, CalibrationState.WEST_MIDDLE}, | ||
55 | + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.CENTER}, | ||
56 | + {CalibrationState.CENTER, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE}, | ||
57 | + }; | ||
58 | + | ||
59 | + public static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); | ||
60 | + | ||
61 | + public static enum CalibrationEvent { | ||
62 | + SCREEN_CHANGED, STARTED, FINISHED, ABORTED, LOADED, SAVED; | ||
63 | + }; | ||
64 | + | ||
65 | + public static interface CalibrationEventListener { | ||
66 | + public void calibrationEvent(CalibrationEvent e); | ||
67 | + } | ||
68 | + | ||
69 | + public static enum CalibrationState { | ||
70 | + DONE(0, 0, null), CENTER(.5, .5, DONE), EAST_MIDDLE(.9, .5, CENTER), WEST_MIDDLE(.1, .5, EAST_MIDDLE), TOP_MIDDLE(.5, .1, WEST_MIDDLE), BOTTOM_MIDDLE(.5, .9, TOP_MIDDLE), LOWER_LEFT(.1, .9, BOTTOM_MIDDLE), LOWER_RIGHT(.9, .9, LOWER_LEFT), UPPER_RIGHT(.9, .1, LOWER_RIGHT), UPPER_LEFT(.1, .1, UPPER_RIGHT), PENDING(0, 0, UPPER_LEFT); | ||
71 | + | ||
72 | + public static final CalibrationState REGULAR_END = LOWER_LEFT; | ||
73 | + private final double xMargin, yMargin; | ||
74 | + private final CalibrationState next; | ||
75 | + | ||
76 | + private CalibrationState(double xMargin, double yMargin, CalibrationState next) { | ||
77 | + this.xMargin = xMargin; | ||
78 | + this.yMargin = yMargin; | ||
79 | + this.next = next; | ||
80 | + } | ||
81 | + | ||
82 | + public int getX(Rectangle bounds) { | ||
83 | + return bounds.x + (int) Math.round(bounds.width * xMargin); | ||
84 | + } | ||
85 | + | ||
86 | + public int getY(Rectangle bounds) { | ||
87 | + return bounds.y + (int) Math.round(bounds.height * yMargin); | ||
88 | + } | ||
89 | + | ||
90 | + public CalibrationState getNext() { | ||
91 | + return next; | ||
92 | + } | ||
93 | + }; | ||
94 | + | ||
95 | + private static final double EPS = .05; | ||
96 | + | ||
97 | + private final CalibrationFrame calibrationFrame; | ||
98 | + private final Set<CalibrationEventListener> listener = new LinkedHashSet<CalibrationEventListener>(); | ||
99 | + | ||
100 | + | ||
101 | + private GraphicsDevice screen = null; | ||
102 | + private int screenNumber = -1; | ||
103 | + private Rectangle bounds; | ||
104 | + private int sc = 0; | ||
105 | + private boolean stepChange = false; | ||
106 | + private boolean checkPoints = false; | ||
107 | + private Collection<Wiimote> wiimotes; | ||
108 | + private CalibrationState state = CalibrationState.PENDING; | ||
109 | + | ||
110 | + // last calibration point for a wiimote, always non-null | ||
111 | + private Map<Wiimote, Point2D> last = new HashMap<Wiimote, Point2D>(); | ||
112 | + // transformer for wiimote | ||
113 | + private Map<String, PerspectiveTransform> transformer = new LinkedHashMap<String, PerspectiveTransform>(); | ||
114 | + // all visible calibration points for each wiimote (can be more than 4) | ||
115 | + private Map<Wiimote, Map<CalibrationState, Point2D>> points = new LinkedHashMap<Wiimote, Map<CalibrationState,Point2D>>(); | ||
116 | + // final 16 value double array (4<->4 mapping) for each wiimote, used to create transformer | ||
117 | + private Map<String, Double[]> finals = new LinkedHashMap<String, Double[]>(); | ||
118 | + | ||
119 | + | ||
120 | + | ||
121 | + public WiimoteCalibration() { | ||
122 | + calibrationFrame = new CalibrationFrame(); | ||
123 | + } | ||
124 | + | ||
125 | + public boolean setScreen(GraphicsDevice screen) { | ||
126 | + if (!inProgress()) { | ||
127 | + this.screen = screen; | ||
128 | + bounds = screen.getDefaultConfiguration().getBounds(); | ||
129 | + calibrationFrame.setBounds(bounds); | ||
130 | + | ||
131 | + // get "screen number" | ||
132 | + GraphicsDevice[] gds = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); | ||
133 | + for (int i = 0; i < gds.length; i++) { | ||
134 | + if (gds[i] == screen) { | ||
135 | + screenNumber = i + 1; | ||
136 | + break; | ||
137 | + } | ||
138 | + } | ||
139 | + | ||
140 | + state = CalibrationState.PENDING; | ||
141 | + transformer.clear(); | ||
142 | + notifyListener(CalibrationEvent.SCREEN_CHANGED); | ||
143 | + return true; | ||
144 | + } else { | ||
145 | + System.err.println("Calibration in Progress."); | ||
146 | + return false; | ||
147 | + } | ||
148 | + } | ||
149 | + | ||
150 | + public GraphicsDevice getScreen() { | ||
151 | + return screen; | ||
152 | + } | ||
153 | + | ||
154 | + public int getScreenNumber() { | ||
155 | + return screenNumber; | ||
156 | + } | ||
157 | + | ||
158 | + @SuppressWarnings("serial") | ||
159 | + private class CalibrationFrame extends JFrame { | ||
160 | + private final ImageIcon VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-ok.png")); | ||
161 | + private final ImageIcon NOT_VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-warning.png")); | ||
162 | + private final Image CROSS_HAIR = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-crosshair.png")).getImage(); | ||
163 | + | ||
164 | + public CalibrationFrame() { | ||
165 | + super("Calibration"); | ||
166 | + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); | ||
167 | + setBackground(Color.WHITE); | ||
168 | + ((JPanel)getContentPane()).setOpaque(true); | ||
169 | + setLayout(null); | ||
170 | + setUndecorated(true); | ||
171 | + setAlwaysOnTop(true); | ||
172 | + addKeyListener(new KeyAdapter() { | ||
173 | + @Override | ||
174 | + public void keyPressed(KeyEvent e) { | ||
175 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
176 | + state = isAnyCalibrated(wiimotes) ? CalibrationState.DONE : CalibrationState.PENDING; | ||
177 | + if (screen.getFullScreenWindow() == calibrationFrame) | ||
178 | + screen.setFullScreenWindow(null); | ||
179 | + setVisible(false); | ||
180 | + notifyListener(CalibrationEvent.ABORTED); | ||
181 | + } | ||
182 | + } | ||
183 | + }); | ||
184 | + } | ||
185 | + | ||
186 | + private JLabel statusLabel(Icon icon, int id, int x, int y) { | ||
187 | + JLabel l = new JLabel(icon, SwingConstants.LEFT); | ||
188 | + if (wiimotes.size() > 1) l.setText(String.valueOf(id)); | ||
189 | + int w = 100; | ||
190 | + int h = icon.getIconHeight(); | ||
191 | + x = x - icon.getIconWidth()/2; | ||
192 | + y = y - wiimotes.size()*h/2; | ||
193 | + l.setBounds(x, y + (id-1)*h, w, h); | ||
194 | + return l; | ||
195 | + } | ||
196 | + | ||
197 | + public void finished(CalibrationState s) { | ||
198 | + int x = s.getX(bounds) - bounds.x; | ||
199 | + int y = s.getY(bounds) - bounds.y; | ||
200 | + | ||
201 | + for (Wiimote wiimote : points.keySet()) { | ||
202 | + add(statusLabel(points.get(wiimote).get(s) != null ? VISIBLE : NOT_VISIBLE, wiimote.getId(), x, y)); | ||
203 | + } | ||
204 | + | ||
205 | + repaint(); | ||
206 | + } | ||
207 | + | ||
208 | + public void reset() { | ||
209 | + getContentPane().removeAll(); | ||
210 | + JLabel info = Util.newComponent(JLabel.class, "infoLabel"); | ||
211 | + info.setFont(info.getFont().deriveFont(20f)); | ||
212 | + info.setHorizontalAlignment(SwingConstants.CENTER); | ||
213 | + int w = bounds.width; | ||
214 | + int h = 200; | ||
215 | + info.setBounds(bounds.width/2 - w/2, bounds.height/3 - h/2, w, h); | ||
216 | + add(info); | ||
217 | + Util.getResourceMap(WiimoteCalibration.class).injectComponents(this); | ||
218 | + } | ||
219 | + | ||
220 | + @Override | ||
221 | + public void paint(Graphics g) { | ||
222 | + super.paint(g); | ||
223 | + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
224 | + | ||
225 | + if (state != CalibrationState.DONE && state != CalibrationState.PENDING) { | ||
226 | + int x = state.getX(bounds) - bounds.x; | ||
227 | + int y = state.getY(bounds) - bounds.y; | ||
228 | + g.drawImage(CROSS_HAIR, x - CROSS_HAIR.getWidth(null)/2 + 1, y - CROSS_HAIR.getHeight(null)/2 + 1, null); | ||
229 | + } | ||
230 | + } | ||
231 | + | ||
232 | + } | ||
233 | + | ||
234 | + public void start(Collection<Wiimote> wiimotes) { | ||
235 | + last.clear(); | ||
236 | + points.clear(); | ||
237 | + finals.clear(); | ||
238 | + calibrationFrame.reset(); | ||
239 | + stepChange = false; | ||
240 | + sc = 0; | ||
241 | + checkPoints = false; | ||
242 | + state = CalibrationState.PENDING.getNext(); | ||
243 | + | ||
244 | + this.wiimotes = wiimotes; | ||
245 | + for (Wiimote wiimote : wiimotes) { | ||
246 | + points.put(wiimote, new LinkedHashMap<CalibrationState, Point2D>()); | ||
247 | + last.put(wiimote, new Point2D.Double(-1,-1)); | ||
248 | + } | ||
249 | + | ||
250 | + if (screen == null) | ||
251 | + setScreen(DEFAULT_SCREEN); | ||
252 | + | ||
253 | + if (Util.MAC_OS_X && screen == DEFAULT_SCREEN) | ||
254 | + screen.setFullScreenWindow(calibrationFrame); | ||
255 | + | ||
256 | + calibrationFrame.repaint(); | ||
257 | + calibrationFrame.setVisible(true); | ||
258 | + notifyListener(CalibrationEvent.STARTED); | ||
259 | + } | ||
260 | + | ||
261 | + public boolean inProgress() { | ||
262 | + return !isPending() && !isDone(); | ||
263 | + } | ||
264 | + | ||
265 | + public boolean isPending() { | ||
266 | + return state == CalibrationState.PENDING; | ||
267 | + } | ||
268 | + | ||
269 | + public boolean isDone() { | ||
270 | + return state == CalibrationState.DONE; | ||
271 | + } | ||
272 | + | ||
273 | + public Map<String, Double[]> getFinals() { | ||
274 | + return finals; | ||
275 | + } | ||
276 | + | ||
277 | + public boolean isCalibrated(Wiimote wiimote) { | ||
278 | + return transformer.containsKey(wiimote.getAddress()); | ||
279 | + } | ||
280 | + | ||
281 | + public boolean isAnyCalibrated(Collection<Wiimote> wiimotes) { | ||
282 | + for (Wiimote wiimote : wiimotes) { | ||
283 | + if (isCalibrated(wiimote)) | ||
284 | + return true; | ||
285 | + } | ||
286 | + return false; | ||
287 | + } | ||
288 | + | ||
289 | + public boolean process(Map<Wiimote, IRDot[]> data) { | ||
290 | + | ||
291 | + if (inProgress()) { | ||
292 | + | ||
293 | + for (Wiimote wiimote : points.keySet()) { | ||
294 | + Point2D lastP = last.get(wiimote); | ||
295 | + Point2D currentP = data.get(wiimote)[0]; | ||
296 | + | ||
297 | + if (currentP != null && lastP.distance(currentP) > EPS) { | ||
298 | + | ||
299 | + points.get(wiimote).put(state, currentP); | ||
300 | + last.put(wiimote, currentP); | ||
301 | + stepChange = true; | ||
302 | + } | ||
303 | + } | ||
304 | + | ||
305 | + // process at least 5 points to not miss a signal | ||
306 | + if (stepChange && ++sc > 5) { | ||
307 | + sc = 0; | ||
308 | + stepChange = false; | ||
309 | + CalibrationState current = state; | ||
310 | + state = state.getNext(); | ||
311 | + calibrationFrame.finished(current); | ||
312 | + | ||
313 | + if (checkPoints || current == CalibrationState.REGULAR_END) { | ||
314 | + checkPoints = true; | ||
315 | + if (calculateQuadsForWiimotes()) { | ||
316 | + // OK, calibration finished | ||
317 | + state = CalibrationState.DONE; | ||
318 | + calculateTransformation(); | ||
319 | + if (screen.getFullScreenWindow() == calibrationFrame) | ||
320 | + screen.setFullScreenWindow(null); | ||
321 | + calibrationFrame.setVisible(false); | ||
322 | + notifyListener(CalibrationEvent.FINISHED); | ||
323 | + return true; | ||
324 | + } else { | ||
325 | + // Go on | ||
326 | + } | ||
327 | + } | ||
328 | + } | ||
329 | + | ||
330 | + if (state == CalibrationState.DONE) { | ||
331 | + // PROBLEM, no solution found | ||
332 | + state = CalibrationState.PENDING; | ||
333 | + if (screen.getFullScreenWindow() == calibrationFrame) | ||
334 | + screen.setFullScreenWindow(null); | ||
335 | + calibrationFrame.setVisible(false); | ||
336 | + notifyListener(CalibrationEvent.ABORTED); | ||
337 | + new Thread(new Runnable() { | ||
338 | + public void run() { | ||
339 | + JOptionPane.showMessageDialog(null, Util.getResourceMap(WiimoteCalibration.class).getString("coverageError"), Util.getResourceMap(WiimoteCalibration.class).getString("calibrationFailed"), JOptionPane.ERROR_MESSAGE); | ||
340 | + } | ||
341 | + }).start(); | ||
342 | + } | ||
343 | + | ||
344 | + return true; | ||
345 | + } | ||
346 | + | ||
347 | + return false; | ||
348 | + } | ||
349 | + | ||
350 | + private static boolean checkExist(Map<CalibrationState, Point2D> p, CalibrationState... states) { | ||
351 | + for (CalibrationState s : states) { | ||
352 | + if (p.get(s) == null) | ||
353 | + return false; | ||
354 | + } | ||
355 | + return true; | ||
356 | + } | ||
357 | + | ||
358 | + private boolean calculateQuadsForWiimotes() { | ||
359 | + boolean success = true; | ||
360 | + Set<CalibrationState> check = new HashSet<CalibrationState>(); | ||
361 | + | ||
362 | + for (Wiimote wiimote : points.keySet()) { | ||
363 | + boolean ok = false; | ||
364 | + | ||
365 | + for (int i = 0; i < VALID_STATES.length; i++) { | ||
366 | + if (checkExist(points.get(wiimote), VALID_STATES[i])) { | ||
367 | + Map<CalibrationState, Point2D> calibrated = points.get(wiimote); | ||
368 | + CalibrationState[] states = VALID_STATES[i]; | ||
369 | + check.addAll(Arrays.asList(states)); | ||
370 | + finals.put(wiimote.getAddress(), new Double[] { | ||
371 | + calibrated.get(states[0]).getX(), calibrated.get(states[0]).getY(), | ||
372 | + calibrated.get(states[1]).getX(), calibrated.get(states[1]).getY(), | ||
373 | + calibrated.get(states[2]).getX(), calibrated.get(states[2]).getY(), | ||
374 | + calibrated.get(states[3]).getX(), calibrated.get(states[3]).getY(), | ||
375 | + (double)states[0].getX(bounds), (double)states[0].getY(bounds), | ||
376 | + (double)states[1].getX(bounds), (double)states[1].getY(bounds), | ||
377 | + (double)states[2].getX(bounds), (double)states[2].getY(bounds), | ||
378 | + (double)states[3].getX(bounds), (double)states[3].getY(bounds) | ||
379 | + }); | ||
380 | + ok = true; | ||
381 | + break; | ||
382 | + } | ||
383 | + } | ||
384 | + | ||
385 | + success = success && ok; | ||
386 | + } | ||
387 | + // check also if the whole screen is covered | ||
388 | + return success && check.containsAll(Arrays.asList(VALID_STATES[0])); | ||
389 | + } | ||
390 | + | ||
391 | + private void calculateTransformation() { | ||
392 | + transformer.clear(); | ||
393 | + for (String address : finals.keySet()) { | ||
394 | + Double[] d = finals.get(address); | ||
395 | + transformer.put(address, PerspectiveTransform.getQuadToQuad(d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15])); | ||
396 | + } | ||
397 | + } | ||
398 | + | ||
399 | + public Map<String, PerspectiveTransform> getTransformer() { | ||
400 | + return transformer; | ||
401 | + } | ||
402 | + | ||
403 | + public IRDot warp(int i, Wiimote wiimote, Map<Wiimote, IRDot[]> data) { | ||
404 | + final PerspectiveTransform transform = transformer.get(wiimote.getAddress()); | ||
405 | + if (transform == null || data.get(wiimote)[i] == null) return null; | ||
406 | + else { | ||
407 | + return (IRDot) transform.transform(data.get(wiimote)[i], new IRDot(data.get(wiimote)[i])); | ||
408 | + } | ||
409 | + } | ||
410 | + | ||
411 | + private Map<Wiimote, IRDot[]> warpIndividually(Map<Wiimote, IRDot[]> data) { | ||
412 | + Map<Wiimote, IRDot[]> warped = new LinkedHashMap<Wiimote, IRDot[]>(); | ||
413 | + IRDot[] p; | ||
414 | + for (Wiimote wiimote : data.keySet()) { | ||
415 | + warped.put(wiimote, p = new IRDot[4]); | ||
416 | + for (int i = 0; i < 4; i++) { | ||
417 | + p[i] = warp(i, wiimote, data); | ||
418 | + } | ||
419 | + } | ||
420 | + return warped; | ||
421 | + } | ||
422 | + | ||
423 | + public Point[] warp(Map<Wiimote, IRDot[]> data) { | ||
424 | + Point[] warped = new Point[4]; | ||
425 | + if (isDone() && isAnyCalibrated(data.keySet())) { | ||
426 | + IRDot[][] cluster = PointClusterer.cluster(warpIndividually(data)); | ||
427 | + | ||
428 | + for (int i = 0; i < cluster.length; i++) { | ||
429 | + if (cluster[i] == null) break; | ||
430 | + double x = 0, y = 0; | ||
431 | + int c = 0; | ||
432 | + for (IRDot p : cluster[i]) { | ||
433 | + x += p.getX(); | ||
434 | + y += p.getY(); | ||
435 | + c++; | ||
436 | + break; | ||
437 | + } | ||
438 | + warped[i] = new Point((int) Math.round(x / c), (int) Math.round(y / c)); | ||
439 | + } | ||
440 | + } else { | ||
441 | + System.err.println("Not calibrated."); | ||
442 | + } | ||
443 | + return warped; | ||
444 | + } | ||
445 | + | ||
446 | + | ||
447 | + public boolean load(InputStream is) throws IOException { | ||
448 | + try { | ||
449 | + BufferedReader in = new BufferedReader(new InputStreamReader(is)); | ||
450 | + String address = null; | ||
451 | + | ||
452 | + while ((address = in.readLine()) != null) { | ||
453 | + Double[] d = new Double[16]; | ||
454 | + finals.put(address, d); | ||
455 | + for (int i = 0; i < 4; i++) { | ||
456 | + String[] p = in.readLine().split(" "); | ||
457 | + for (int j = 0; j < 2; j++) { | ||
458 | + d[i*2+j+0] = Double.valueOf(p[j+0]); | ||
459 | + d[i*2+j+8] = Double.valueOf(p[j+2]); | ||
460 | + } | ||
461 | + } | ||
462 | + } | ||
463 | + | ||
464 | + calculateTransformation(); | ||
465 | + state = CalibrationState.DONE; | ||
466 | + notifyListener(CalibrationEvent.LOADED); | ||
467 | + return true; | ||
468 | + | ||
469 | + } catch (Exception e) { | ||
470 | + e.printStackTrace(); | ||
471 | + return false; | ||
472 | + } | ||
473 | + } | ||
474 | + | ||
475 | + public void save(OutputStream os) throws IOException { | ||
476 | + PrintStream out = new PrintStream(os); | ||
477 | + | ||
478 | + for (String address : finals.keySet()) { | ||
479 | + out.print(address); | ||
480 | + Double[] d = finals.get(address); | ||
481 | + for (int i = 0; i < 4; i++) { | ||
482 | + out.printf(Locale.ENGLISH, "\n%f %f %.0f %.0f", d[i*2+0+0], d[i*2+1+0], d[i*2+0+8], d[i*2+1+8]); | ||
483 | + } | ||
484 | + out.println(); | ||
485 | + } | ||
486 | + out.close(); | ||
487 | + | ||
488 | + notifyListener(CalibrationEvent.SAVED); | ||
489 | + } | ||
490 | + | ||
491 | + | ||
492 | + /* | ||
493 | + * LISTENER | ||
494 | + */ | ||
495 | + | ||
496 | + public void addCalibrationEventListener(CalibrationEventListener l) { | ||
497 | + listener.add(l); | ||
498 | + } | ||
499 | + | ||
500 | + public void removeCalibrationEventListener(CalibrationEventListener l) { | ||
501 | + listener.remove(l); | ||
502 | + } | ||
503 | + | ||
504 | + private void notifyListener(CalibrationEvent e) { | ||
505 | + WiimoteWhiteboard.getLogger().info("Calibration Event: " + e); | ||
506 | + for (CalibrationEventListener l : listener) { | ||
507 | + l.calibrationEvent(e); | ||
508 | + } | ||
509 | + } | ||
510 | + | ||
511 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/WiimoteCalibration.java~
0 → 100644
@@ -0,0 +1,511 @@ | @@ -0,0 +1,511 @@ | ||
1 | +package org.mote.wiimote.whiteboard.calibration; | ||
2 | +import java.awt.Color; | ||
3 | +import java.awt.Graphics; | ||
4 | +import java.awt.Graphics2D; | ||
5 | +import java.awt.GraphicsDevice; | ||
6 | +import java.awt.GraphicsEnvironment; | ||
7 | +import java.awt.Image; | ||
8 | +import java.awt.Point; | ||
9 | +import java.awt.Rectangle; | ||
10 | +import java.awt.RenderingHints; | ||
11 | +import java.awt.event.KeyAdapter; | ||
12 | +import java.awt.event.KeyEvent; | ||
13 | +import java.awt.geom.Point2D; | ||
14 | +import java.io.BufferedReader; | ||
15 | +import java.io.IOException; | ||
16 | +import java.io.InputStream; | ||
17 | +import java.io.InputStreamReader; | ||
18 | +import java.io.OutputStream; | ||
19 | +import java.io.PrintStream; | ||
20 | +import java.util.Arrays; | ||
21 | +import java.util.Collection; | ||
22 | +import java.util.HashMap; | ||
23 | +import java.util.HashSet; | ||
24 | +import java.util.LinkedHashMap; | ||
25 | +import java.util.LinkedHashSet; | ||
26 | +import java.util.Locale; | ||
27 | +import java.util.Map; | ||
28 | +import java.util.Set; | ||
29 | + | ||
30 | +import javax.media.jai.PerspectiveTransform; | ||
31 | +import javax.swing.Icon; | ||
32 | +import javax.swing.ImageIcon; | ||
33 | +import javax.swing.JFrame; | ||
34 | +import javax.swing.JLabel; | ||
35 | +import javax.swing.JOptionPane; | ||
36 | +import javax.swing.JPanel; | ||
37 | +import javax.swing.SwingConstants; | ||
38 | + | ||
39 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
40 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
41 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
42 | +import org.mote.wiimote.whiteboard.util.Util; | ||
43 | + | ||
44 | +public class WiimoteCalibration { | ||
45 | + | ||
46 | + // list of all "rectangles" of the 3x3 calibration grid, larger to smaller | ||
47 | + private static final CalibrationState[][] VALID_STATES = { | ||
48 | + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT}, | ||
49 | + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT}, | ||
50 | + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE}, | ||
51 | + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.WEST_MIDDLE}, | ||
52 | + {CalibrationState.WEST_MIDDLE, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT}, | ||
53 | + {CalibrationState.WEST_MIDDLE, CalibrationState.CENTER, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT}, | ||
54 | + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.CENTER, CalibrationState.WEST_MIDDLE}, | ||
55 | + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.CENTER}, | ||
56 | + {CalibrationState.CENTER, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE}, | ||
57 | + }; | ||
58 | + | ||
59 | + public static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); | ||
60 | + | ||
61 | + public static enum CalibrationEvent { | ||
62 | + SCREEN_CHANGED, STARTED, FINISHED, ABORTED, LOADED, SAVED; | ||
63 | + }; | ||
64 | + | ||
65 | + public static interface CalibrationEventListener { | ||
66 | + public void calibrationEvent(CalibrationEvent e); | ||
67 | + } | ||
68 | + | ||
69 | + public static enum CalibrationState { | ||
70 | + DONE(0, 0, null), CENTER(.5, .5, DONE), EAST_MIDDLE(.9, .5, CENTER), WEST_MIDDLE(.1, .5, EAST_MIDDLE), TOP_MIDDLE(.5, .1, WEST_MIDDLE), BOTTOM_MIDDLE(.5, .9, TOP_MIDDLE), LOWER_LEFT(.1, .9, BOTTOM_MIDDLE), LOWER_RIGHT(.9, .9, LOWER_LEFT), UPPER_RIGHT(.9, .1, LOWER_RIGHT), UPPER_LEFT(.1, .1, UPPER_RIGHT), PENDING(0, 0, UPPER_LEFT); | ||
71 | + | ||
72 | + public static final CalibrationState REGULAR_END = LOWER_LEFT; | ||
73 | + private final double xMargin, yMargin; | ||
74 | + private final CalibrationState next; | ||
75 | + | ||
76 | + private CalibrationState(double xMargin, double yMargin, CalibrationState next) { | ||
77 | + this.xMargin = xMargin; | ||
78 | + this.yMargin = yMargin; | ||
79 | + this.next = next; | ||
80 | + } | ||
81 | + | ||
82 | + public int getX(Rectangle bounds) { | ||
83 | + return bounds.x + (int) Math.round(bounds.width * xMargin); | ||
84 | + } | ||
85 | + | ||
86 | + public int getY(Rectangle bounds) { | ||
87 | + return bounds.y + (int) Math.round(bounds.height * yMargin); | ||
88 | + } | ||
89 | + | ||
90 | + public CalibrationState getNext() { | ||
91 | + return next; | ||
92 | + } | ||
93 | + }; | ||
94 | + | ||
95 | + private static final double EPS = .05; | ||
96 | + | ||
97 | + private final CalibrationFrame calibrationFrame; | ||
98 | + private final Set<CalibrationEventListener> listener = new LinkedHashSet<CalibrationEventListener>(); | ||
99 | + | ||
100 | + | ||
101 | + private GraphicsDevice screen = null; | ||
102 | + private int screenNumber = -1; | ||
103 | + private Rectangle bounds; | ||
104 | + private int sc = 0; | ||
105 | + private boolean stepChange = false; | ||
106 | + private boolean checkPoints = false; | ||
107 | + private Collection<Wiimote> wiimotes; | ||
108 | + private CalibrationState state = CalibrationState.PENDING; | ||
109 | + | ||
110 | + // last calibration point for a wiimote, always non-null | ||
111 | + private Map<Wiimote, Point2D> last = new HashMap<Wiimote, Point2D>(); | ||
112 | + // transformer for wiimote | ||
113 | + private Map<String, PerspectiveTransform> transformer = new LinkedHashMap<String, PerspectiveTransform>(); | ||
114 | + // all visible calibration points for each wiimote (can be more than 4) | ||
115 | + private Map<Wiimote, Map<CalibrationState, Point2D>> points = new LinkedHashMap<Wiimote, Map<CalibrationState,Point2D>>(); | ||
116 | + // final 16 value double array (4<->4 mapping) for each wiimote, used to create transformer | ||
117 | + private Map<String, Double[]> finals = new LinkedHashMap<String, Double[]>(); | ||
118 | + | ||
119 | + | ||
120 | + | ||
121 | + public WiimoteCalibration() { | ||
122 | + calibrationFrame = new CalibrationFrame(); | ||
123 | + } | ||
124 | + | ||
125 | + public boolean setScreen(GraphicsDevice screen) { | ||
126 | + if (!inProgress()) { | ||
127 | + this.screen = screen; | ||
128 | + bounds = screen.getDefaultConfiguration().getBounds(); | ||
129 | + calibrationFrame.setBounds(bounds); | ||
130 | + | ||
131 | + // get "screen number" | ||
132 | + GraphicsDevice[] gds = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); | ||
133 | + for (int i = 0; i < gds.length; i++) { | ||
134 | + if (gds[i] == screen) { | ||
135 | + screenNumber = i + 1; | ||
136 | + break; | ||
137 | + } | ||
138 | + } | ||
139 | + | ||
140 | + state = CalibrationState.PENDING; | ||
141 | + transformer.clear(); | ||
142 | + notifyListener(CalibrationEvent.SCREEN_CHANGED); | ||
143 | + return true; | ||
144 | + } else { | ||
145 | + System.err.println("Calibration in Progress."); | ||
146 | + return false; | ||
147 | + } | ||
148 | + } | ||
149 | + | ||
150 | + public GraphicsDevice getScreen() { | ||
151 | + return screen; | ||
152 | + } | ||
153 | + | ||
154 | + public int getScreenNumber() { | ||
155 | + return screenNumber; | ||
156 | + } | ||
157 | + | ||
158 | + @SuppressWarnings("serial") | ||
159 | + private class CalibrationFrame extends JFrame { | ||
160 | + private final ImageIcon VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-ok.png")); | ||
161 | + private final ImageIcon NOT_VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-warning.png")); | ||
162 | + private final Image CROSS_HAIR = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-crosshair.png")).getImage(); | ||
163 | + | ||
164 | + public CalibrationFrame() { | ||
165 | + super("Calibration"); | ||
166 | + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); | ||
167 | + setBackground(Color.WHITE); | ||
168 | + ((JPanel)getContentPane()).setOpaque(true); | ||
169 | + setLayout(null); | ||
170 | + setUndecorated(true); | ||
171 | + setAlwaysOnTop(true); | ||
172 | + addKeyListener(new KeyAdapter() { | ||
173 | + @Override | ||
174 | + public void keyPressed(KeyEvent e) { | ||
175 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
176 | + state = isAnyCalibrated(wiimotes) ? CalibrationState.DONE : CalibrationState.PENDING; | ||
177 | + if (screen.getFullScreenWindow() == calibrationFrame) | ||
178 | + screen.setFullScreenWindow(null); | ||
179 | + setVisible(false); | ||
180 | + notifyListener(CalibrationEvent.ABORTED); | ||
181 | + } | ||
182 | + } | ||
183 | + }); | ||
184 | + } | ||
185 | + | ||
186 | + private JLabel statusLabel(Icon icon, int id, int x, int y) { | ||
187 | + JLabel l = new JLabel(icon, SwingConstants.LEFT); | ||
188 | + if (wiimotes.size() > 1) l.setText(String.valueOf(id)); | ||
189 | + int w = 100; | ||
190 | + int h = icon.getIconHeight(); | ||
191 | + x = x - icon.getIconWidth()/2; | ||
192 | + y = y - wiimotes.size()*h/2; | ||
193 | + l.setBounds(x, y + (id-1)*h, w, h); | ||
194 | + return l; | ||
195 | + } | ||
196 | + | ||
197 | + public void finished(CalibrationState s) { | ||
198 | + int x = s.getX(bounds) - bounds.x; | ||
199 | + int y = s.getY(bounds) - bounds.y; | ||
200 | + | ||
201 | + for (Wiimote wiimote : points.keySet()) { | ||
202 | + add(statusLabel(points.get(wiimote).get(s) != null ? VISIBLE : NOT_VISIBLE, wiimote.getId(), x, y)); | ||
203 | + } | ||
204 | + | ||
205 | + repaint(); | ||
206 | + } | ||
207 | + | ||
208 | + public void reset() { | ||
209 | + getContentPane().removeAll(); | ||
210 | + JLabel info = Util.newComponent(JLabel.class, "infoLabel"); | ||
211 | + info.setFont(info.getFont().deriveFont(20f)); | ||
212 | + info.setHorizontalAlignment(SwingConstants.CENTER); | ||
213 | + int w = bounds.width; | ||
214 | + int h = 200; | ||
215 | + info.setBounds(bounds.width/2 - w/2, bounds.height/3 - h/2, w, h); | ||
216 | + add(info); | ||
217 | + Util.getResourceMap(WiimoteCalibration.class).injectComponents(this); | ||
218 | + } | ||
219 | + | ||
220 | + @Override | ||
221 | + public void paint(Graphics g) { | ||
222 | + super.paint(g); | ||
223 | + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
224 | + | ||
225 | + if (state != CalibrationState.DONE && state != CalibrationState.PENDING) { | ||
226 | + int x = state.getX(bounds) - bounds.x; | ||
227 | + int y = state.getY(bounds) - bounds.y; | ||
228 | + g.drawImage(CROSS_HAIR, x - CROSS_HAIR.getWidth(null)/2 + 1, y - CROSS_HAIR.getHeight(null)/2 + 1, null); | ||
229 | + } | ||
230 | + } | ||
231 | + | ||
232 | + } | ||
233 | + | ||
234 | + public void start(Collection<Wiimote> wiimotes) { | ||
235 | + last.clear(); | ||
236 | + points.clear(); | ||
237 | + finals.clear(); | ||
238 | + calibrationFrame.reset(); | ||
239 | + stepChange = false; | ||
240 | + sc = 0; | ||
241 | + checkPoints = false; | ||
242 | + state = CalibrationState.PENDING.getNext(); | ||
243 | + | ||
244 | + this.wiimotes = wiimotes; | ||
245 | + for (Wiimote wiimote : wiimotes) { | ||
246 | + points.put(wiimote, new LinkedHashMap<CalibrationState, Point2D>()); | ||
247 | + last.put(wiimote, new Point2D.Double(-1,-1)); | ||
248 | + } | ||
249 | + | ||
250 | + if (screen == null) | ||
251 | + setScreen(DEFAULT_SCREEN); | ||
252 | + | ||
253 | + if (Util.MAC_OS_X && screen == DEFAULT_SCREEN) | ||
254 | + screen.setFullScreenWindow(calibrationFrame); | ||
255 | + | ||
256 | + calibrationFrame.repaint(); | ||
257 | + calibrationFrame.setVisible(true); | ||
258 | + notifyListener(CalibrationEvent.STARTED); | ||
259 | + } | ||
260 | + | ||
261 | + public boolean inProgress() { | ||
262 | + return !isPending() && !isDone(); | ||
263 | + } | ||
264 | + | ||
265 | + public boolean isPending() { | ||
266 | + return state == CalibrationState.PENDING; | ||
267 | + } | ||
268 | + | ||
269 | + public boolean isDone() { | ||
270 | + return state == CalibrationState.DONE; | ||
271 | + } | ||
272 | + | ||
273 | + public Map<String, Double[]> getFinals() { | ||
274 | + return finals; | ||
275 | + } | ||
276 | + | ||
277 | + public boolean isCalibrated(Wiimote wiimote) { | ||
278 | + return transformer.containsKey(wiimote.getAddress()); | ||
279 | + } | ||
280 | + | ||
281 | + public boolean isAnyCalibrated(Collection<Wiimote> wiimotes) { | ||
282 | + for (Wiimote wiimote : wiimotes) { | ||
283 | + if (isCalibrated(wiimote)) | ||
284 | + return true; | ||
285 | + } | ||
286 | + return false; | ||
287 | + } | ||
288 | + | ||
289 | + public boolean process(Map<Wiimote, IRDot[]> data) { | ||
290 | + | ||
291 | + if (inProgress()) { | ||
292 | + | ||
293 | + for (Wiimote wiimote : points.keySet()) { | ||
294 | + Point2D lastP = last.get(wiimote); | ||
295 | + Point2D currentP = data.get(wiimote)[0]; | ||
296 | + | ||
297 | + if (currentP != null && lastP.distance(currentP) > EPS) { | ||
298 | + | ||
299 | + points.get(wiimote).put(state, currentP); | ||
300 | + last.put(wiimote, currentP); | ||
301 | + stepChange = true; | ||
302 | + } | ||
303 | + } | ||
304 | + | ||
305 | + // process at least 5 points to not miss a signal | ||
306 | + if (stepChange && ++sc > 5) { | ||
307 | + sc = 0; | ||
308 | + stepChange = false; | ||
309 | + CalibrationState current = state; | ||
310 | + state = state.getNext(); | ||
311 | + calibrationFrame.finished(current); | ||
312 | + | ||
313 | + if (checkPoints || current == CalibrationState.REGULAR_END) { | ||
314 | + checkPoints = true; | ||
315 | + if (calculateQuadsForWiimotes()) { | ||
316 | + // OK, calibration finished | ||
317 | + state = CalibrationState.DONE; | ||
318 | + calculateTransformation(); | ||
319 | + if (screen.getFullScreenWindow() == calibrationFrame) | ||
320 | + screen.setFullScreenWindow(null); | ||
321 | + calibrationFrame.setVisible(false); | ||
322 | + notifyListener(CalibrationEvent.FINISHED); | ||
323 | + return true; | ||
324 | + } else { | ||
325 | + // Go on | ||
326 | + } | ||
327 | + } | ||
328 | + } | ||
329 | + | ||
330 | + if (state == CalibrationState.DONE) { | ||
331 | + // PROBLEM, no solution found | ||
332 | + state = CalibrationState.PENDING; | ||
333 | + if (screen.getFullScreenWindow() == calibrationFrame) | ||
334 | + screen.setFullScreenWindow(null); | ||
335 | + calibrationFrame.setVisible(false); | ||
336 | + notifyListener(CalibrationEvent.ABORTED); | ||
337 | + new Thread(new Runnable() { | ||
338 | + public void run() { | ||
339 | + JOptionPane.showMessageDialog(null, Util.getResourceMap(WiimoteCalibration.class).getString("coverageError"), Util.getResourceMap(WiimoteCalibration.class).getString("calibrationFailed"), JOptionPane.ERROR_MESSAGE); | ||
340 | + } | ||
341 | + }).start(); | ||
342 | + } | ||
343 | + | ||
344 | + return true; | ||
345 | + } | ||
346 | + | ||
347 | + return false; | ||
348 | + } | ||
349 | + | ||
350 | + private static boolean checkExist(Map<CalibrationState, Point2D> p, CalibrationState... states) { | ||
351 | + for (CalibrationState s : states) { | ||
352 | + if (p.get(s) == null) | ||
353 | + return false; | ||
354 | + } | ||
355 | + return true; | ||
356 | + } | ||
357 | + | ||
358 | + private boolean calculateQuadsForWiimotes() { | ||
359 | + boolean success = true; | ||
360 | + Set<CalibrationState> check = new HashSet<CalibrationState>(); | ||
361 | + | ||
362 | + for (Wiimote wiimote : points.keySet()) { | ||
363 | + boolean ok = false; | ||
364 | + | ||
365 | + for (int i = 0; i < VALID_STATES.length; i++) { | ||
366 | + if (checkExist(points.get(wiimote), VALID_STATES[i])) { | ||
367 | + Map<CalibrationState, Point2D> calibrated = points.get(wiimote); | ||
368 | + CalibrationState[] states = VALID_STATES[i]; | ||
369 | + check.addAll(Arrays.asList(states)); | ||
370 | + finals.put(wiimote.getAddress(), new Double[] { | ||
371 | + calibrated.get(states[0]).getX(), calibrated.get(states[0]).getY(), | ||
372 | + calibrated.get(states[1]).getX(), calibrated.get(states[1]).getY(), | ||
373 | + calibrated.get(states[2]).getX(), calibrated.get(states[2]).getY(), | ||
374 | + calibrated.get(states[3]).getX(), calibrated.get(states[3]).getY(), | ||
375 | + (double)states[0].getX(bounds), (double)states[0].getY(bounds), | ||
376 | + (double)states[1].getX(bounds), (double)states[1].getY(bounds), | ||
377 | + (double)states[2].getX(bounds), (double)states[2].getY(bounds), | ||
378 | + (double)states[3].getX(bounds), (double)states[3].getY(bounds) | ||
379 | + }); | ||
380 | + ok = true; | ||
381 | + break; | ||
382 | + } | ||
383 | + } | ||
384 | + | ||
385 | + success = success && ok; | ||
386 | + } | ||
387 | + // check also if the whole screen is covered | ||
388 | + return success && check.containsAll(Arrays.asList(VALID_STATES[0])); | ||
389 | + } | ||
390 | + | ||
391 | + private void calculateTransformation() { | ||
392 | + transformer.clear(); | ||
393 | + for (String address : finals.keySet()) { | ||
394 | + Double[] d = finals.get(address); | ||
395 | + transformer.put(address, PerspectiveTransform.getQuadToQuad(d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15])); | ||
396 | + } | ||
397 | + } | ||
398 | + | ||
399 | + public Map<String, PerspectiveTransform> getTransformer() { | ||
400 | + return transformer; | ||
401 | + } | ||
402 | + | ||
403 | + public IRDot warp(int i, Wiimote wiimote, Map<Wiimote, IRDot[]> data) { | ||
404 | + final PerspectiveTransform transform = transformer.get(wiimote.getAddress()); | ||
405 | + if (transform == null || data.get(wiimote)[i] == null) return null; | ||
406 | + else { | ||
407 | + return (IRDot) transform.transform(data.get(wiimote)[i], new IRDot(data.get(wiimote)[i])); | ||
408 | + } | ||
409 | + } | ||
410 | + | ||
411 | + private Map<Wiimote, IRDot[]> warpIndividually(Map<Wiimote, IRDot[]> data) { | ||
412 | + Map<Wiimote, IRDot[]> warped = new LinkedHashMap<Wiimote, IRDot[]>(); | ||
413 | + IRDot[] p; | ||
414 | + for (Wiimote wiimote : data.keySet()) { | ||
415 | + warped.put(wiimote, p = new IRDot[4]); | ||
416 | + for (int i = 0; i < 4; i++) { | ||
417 | + p[i] = warp(i, wiimote, data); | ||
418 | + } | ||
419 | + } | ||
420 | + return warped; | ||
421 | + } | ||
422 | + | ||
423 | + public Point[] warp(Map<Wiimote, IRDot[]> data) { | ||
424 | + Point[] warped = new Point[4]; | ||
425 | + if (isDone() && isAnyCalibrated(data.keySet())) { | ||
426 | + IRDot[][] cluster = PointClusterer.cluster(warpIndividually(data)); | ||
427 | + | ||
428 | + for (int i = 0; i < cluster.length; i++) { | ||
429 | + if (cluster[i] == null) break; | ||
430 | + double x = 0, y = 0; | ||
431 | + int c = 0; | ||
432 | + for (IRDot p : cluster[i]) { | ||
433 | + x += p.getX(); | ||
434 | + y += p.getY(); | ||
435 | + c++; | ||
436 | + break; | ||
437 | + } | ||
438 | + warped[i] = new Point((int) Math.round(x / c), (int) Math.round(y / c)); | ||
439 | + } | ||
440 | + } else { | ||
441 | + System.err.println("Not calibrated."); | ||
442 | + } | ||
443 | + return warped; | ||
444 | + } | ||
445 | + | ||
446 | + | ||
447 | + public boolean load(InputStream is) throws IOException { | ||
448 | + try { | ||
449 | + BufferedReader in = new BufferedReader(new InputStreamReader(is)); | ||
450 | + String address = null; | ||
451 | + | ||
452 | + while ((address = in.readLine()) != null) { | ||
453 | + Double[] d = new Double[16]; | ||
454 | + finals.put(address, d); | ||
455 | + for (int i = 0; i < 4; i++) { | ||
456 | + String[] p = in.readLine().split(" "); | ||
457 | + for (int j = 0; j < 2; j++) { | ||
458 | + d[i*2+j+0] = Double.valueOf(p[j+0]); | ||
459 | + d[i*2+j+8] = Double.valueOf(p[j+2]); | ||
460 | + } | ||
461 | + } | ||
462 | + } | ||
463 | + | ||
464 | + calculateTransformation(); | ||
465 | + state = CalibrationState.DONE; | ||
466 | + notifyListener(CalibrationEvent.LOADED); | ||
467 | + return true; | ||
468 | + | ||
469 | + } catch (Exception e) { | ||
470 | + e.printStackTrace(); | ||
471 | + return false; | ||
472 | + } | ||
473 | + } | ||
474 | + | ||
475 | + public void save(OutputStream os) throws IOException { | ||
476 | + PrintStream out = new PrintStream(os); | ||
477 | + | ||
478 | + for (String address : finals.keySet()) { | ||
479 | + out.print(address); | ||
480 | + Double[] d = finals.get(address); | ||
481 | + for (int i = 0; i < 4; i++) { | ||
482 | + out.printf(Locale.ENGLISH, "\n%f %f %.0f %.0f", d[i*2+0+0], d[i*2+1+0], d[i*2+0+8], d[i*2+1+8]); | ||
483 | + } | ||
484 | + out.println(); | ||
485 | + } | ||
486 | + out.close(); | ||
487 | + | ||
488 | + notifyListener(CalibrationEvent.SAVED); | ||
489 | + } | ||
490 | + | ||
491 | + | ||
492 | + /* | ||
493 | + * LISTENER STUFF | ||
494 | + */ | ||
495 | + | ||
496 | + public void addCalibrationEventListener(CalibrationEventListener l) { | ||
497 | + listener.add(l); | ||
498 | + } | ||
499 | + | ||
500 | + public void removeCalibrationEventListener(CalibrationEventListener l) { | ||
501 | + listener.remove(l); | ||
502 | + } | ||
503 | + | ||
504 | + private void notifyListener(CalibrationEvent e) { | ||
505 | + WiimoteWhiteboard.getLogger().info("Calibration Event: " + e); | ||
506 | + for (CalibrationEventListener l : listener) { | ||
507 | + l.calibrationEvent(e); | ||
508 | + } | ||
509 | + } | ||
510 | + | ||
511 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration.properties
0 → 100644
@@ -0,0 +1,4 @@ | @@ -0,0 +1,4 @@ | ||
1 | +infoLabel.text = <html><center>Press ESC to abort calibration.<br><br>Make sure all connected Wiimotes can see the screen.</center></html> | ||
2 | + | ||
3 | +calibrationFailed = Calibration failed | ||
4 | +coverageError = The Wiimotes don't seem to cover the whole screen.${nl}Try to reposition them and start again. |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_de.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1265226421,Uwe | ||
2 | + | ||
3 | +infoLabel.text=<html><center>Dr\u00fccke ESC um die Kalibrierung abzubrechen.<br><br>Achte darauf dass alle Wiimotes den Bildschirm gut sehen k\u00f6nnen.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=Kalibrierung fehlgeschlagen | ||
6 | + | ||
7 | +coverageError=Die Wiimotes scheinen nicht den gesamten Bildschirm abzudecken.${nl}Versuche sie neu zu positionieren und starte dann nochmal. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_es.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1224248803,Uwe | ||
2 | + | ||
3 | +infoLabel.text=<html><center>Oprime ESC para cancelar calibraci\u00f3n.<br><br>Aseg\u00farese de que todos los Wiimotes puedan ver la pantalla.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=La calibraci\u00f3n fallo | ||
6 | + | ||
7 | +coverageError=Los Wiimotes no parecen cubrir la pantalla entera.${nl}Cambien la posici\u00f3n de los Wiimotes y reinicie la calibraci\u00f3n. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_et.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1248454359,Marko | ||
2 | + | ||
3 | +infoLabel.text=<html><center>Vajuta ESC klahvi kui soovid kalibreerimist katkestada.<br><br>Veendu, et k\u00f5ik Wii puldid n\u00e4evad kogu ekraani.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=Kalibreerimine eba\u00f5nnestus | ||
6 | + | ||
7 | +coverageError=K\u00f5ik Wii puldid ei n\u00e4e kogu ekraani.${nl}Proovi pultide asendit korrigeerida ning alusta kalibreerimist uuesti. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_fr.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1265226429,Uwe | ||
2 | + | ||
3 | +infoLabel.text=<html><center>Presser ESC pour annuler la calibration.<br><br>V\u00e9rifier que toutes les Wiimotes connect\u00e9s peuvent capter l'\u00e9cran.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=La calibration a \u00e9chou\u00e9 | ||
6 | + | ||
7 | +coverageError=Les Wiimotes ne semblent pas capter la totalit\u00e9 de l'\u00e9cran.${nl}Essayer de les placer mieux et red\u00e9marrer la calibration. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_in.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1274618479,Bobby | ||
2 | + | ||
3 | +infoLabel.text=<html><center>Tekan ESC untuk membatalkan Kalibrasi.<br><br>Pastikan semua Wiimotes yang terhubung dapat melihat layar.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=Kalibrasi gagal | ||
6 | + | ||
7 | +coverageError=Wiimotes nampaknya tidak dapat melihat keseluruhan layar.${nl}Coba ubah posisinya dan mulai lagi dari awal. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_it.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1240167662,Uwe | ||
2 | + | ||
3 | +infoLabel.text=<html><center>Premi ESC per interrompere la calibrazione.<br><br>Assicurati che tutti i Wiimote connessi possano "vedere" lo schermo.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=Calibrazione fallita | ||
6 | + | ||
7 | +coverageError=Il Wiimote non sembra coprire l'intero schermo.${nl}Prova a riposizionarlo, e ritenta. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_pl.properties
0 → 100644
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +#:1253207960,Grzegorz | ||
2 | + | ||
3 | +# Wiimote = Wiilot in Polish | ||
4 | +infoLabel.text=<html><center>Naci\u015bnij ESC aby przerwa\u0107 kalibracj\u0119.<br><br>Sprawd\u017a czy wszystkie pod\u0142\u0105czone Wiiloty widz\u0105 ekran.</center></html> | ||
5 | + | ||
6 | +calibrationFailed=Kalibracja nie powiod\u0142a si\u0119 | ||
7 | + | ||
8 | +coverageError=Wiiloty nie obejmuj\u0105 ca\u0142ego ekranu. Zmie\u0144 ich pozycj\u0119 i spr\u00f3buj ponownie. | ||
9 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_pt.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1224248742,Uwe | ||
2 | + | ||
3 | +infoLabel.text=<html><center>Pressione ESC para abortar a calibra\u00e7\u00e3o.<br><br>Certifique-se que todos os Wiimotes conseguem ver o ecr\u00e3.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=Calibra\u00e7\u00e3o n\u00e3o efectuada | ||
6 | + | ||
7 | +coverageError=Os Wiimotes parecem n\u00e3o abranger toda a \u00e1rea do ecr\u00e3.${nl}Tente outra posi\u00e7\u00e3o e recomece. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_ru.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1265227045,Uwe | ||
2 | + | ||
3 | +infoLabel.text=<html><center>\u041d\u0430\u0436\u043c\u0438\u0442\u0435 ESC \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0440\u0432\u0430\u0442\u044c \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0443.<br><br>\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0441\u0435 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0435 Wiimot'\u044b \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u044d\u043a\u0440\u0430\u043d.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=\u041a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0430 \u043d\u0435 \u0443\u0434\u0430\u043b\u0430\u0441\u044c | ||
6 | + | ||
7 | +coverageError=Wiimote \u043d\u0435 \u0432\u0438\u0434\u0438\u0442 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d \u0446\u0435\u043b\u0438\u043a\u043e\u043c.${nl}\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0438 \u043d\u0430\u0447\u043d\u0438\u0442\u0435 \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0443 \u0441\u043d\u043e\u0432\u0430. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_sl.properties
0 → 100644
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +#:1238601406,Samo | ||
2 | + | ||
3 | +infoLabel.text=<html><center>\u010ce \u017eelite prekiniti kalibracijo, pritisnite tipko ESC.<br><br>Poskrbite, da bodo vsi priklu\u010deni Wiimoti videli ekran ali projekcijsko povr\u0161ino.</center></html> | ||
4 | + | ||
5 | +calibrationFailed=Povezava ni uspela | ||
6 | + | ||
7 | +coverageError=Senzorji Wiimotov ne zaznavajo celotnega ekrana ali projekcijske povr\u0161ine. ${nl}Postavite jih druga\u010de in poskusite znova. | ||
8 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/francisco-crosshair.png
0 → 100644
3.54 KB
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/francisco-ok.png
0 → 100644
4.32 KB
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/francisco-warning.png
0 → 100644
3.66 KB
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/ok.png
0 → 100644
1019 Bytes
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/warning.png
0 → 100644
1.19 KB
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/IRDot.java
0 → 100644
@@ -0,0 +1,47 @@ | @@ -0,0 +1,47 @@ | ||
1 | +package org.mote.wiimote.whiteboard.ds; | ||
2 | + | ||
3 | +import java.awt.geom.Point2D; | ||
4 | + | ||
5 | +import wiiremotej.IRLight; | ||
6 | + | ||
7 | +public class IRDot extends Point2D.Double { | ||
8 | + | ||
9 | + private final int id; | ||
10 | + private double size; | ||
11 | + | ||
12 | + public IRDot(int id, double x, double y, double size) { | ||
13 | + super(x, y); | ||
14 | + this.id = id; | ||
15 | + this.size = size; | ||
16 | + } | ||
17 | + | ||
18 | + public IRDot(IRDot dot) { | ||
19 | + this(dot.getId(), dot.getX(), dot.getY(), dot.getSize()); | ||
20 | + } | ||
21 | + | ||
22 | + public IRDot(int id, IRLight light) { | ||
23 | + this(id, light.getX(), light.getY(), light.getSize()); | ||
24 | + } | ||
25 | + | ||
26 | + @Override | ||
27 | + public String toString() { | ||
28 | + return String.format("[Dot%d: x = %.2f, y = %.2f, s = %.2f]", id, x, y, size); | ||
29 | + } | ||
30 | + | ||
31 | + public double getSize() { | ||
32 | + return size; | ||
33 | + } | ||
34 | + | ||
35 | + public int getId() { | ||
36 | + return id; | ||
37 | + } | ||
38 | + | ||
39 | + public static IRDot[] getIRDots(IRLight[] lights) { | ||
40 | + IRDot[] dots = new IRDot[lights.length]; | ||
41 | + for (int i = 0; i < lights.length; i++) { | ||
42 | + dots[i] = lights[i] == null ? null : new IRDot(i, lights[i]); | ||
43 | + } | ||
44 | + return dots; | ||
45 | + } | ||
46 | + | ||
47 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/IRDot.java~
0 → 100644
@@ -0,0 +1,72 @@ | @@ -0,0 +1,72 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.ds; | ||
27 | + | ||
28 | +import java.awt.geom.Point2D; | ||
29 | + | ||
30 | +import wiiremotej.IRLight; | ||
31 | + | ||
32 | +public class IRDot extends Point2D.Double { | ||
33 | + | ||
34 | + private final int id; | ||
35 | + private double size; | ||
36 | + | ||
37 | + public IRDot(int id, double x, double y, double size) { | ||
38 | + super(x, y); | ||
39 | + this.id = id; | ||
40 | + this.size = size; | ||
41 | + } | ||
42 | + | ||
43 | + public IRDot(IRDot dot) { | ||
44 | + this(dot.getId(), dot.getX(), dot.getY(), dot.getSize()); | ||
45 | + } | ||
46 | + | ||
47 | + public IRDot(int id, IRLight light) { | ||
48 | + this(id, light.getX(), light.getY(), light.getSize()); | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + public String toString() { | ||
53 | + return String.format("[Dot%d: x = %.2f, y = %.2f, s = %.2f]", id, x, y, size); | ||
54 | + } | ||
55 | + | ||
56 | + public double getSize() { | ||
57 | + return size; | ||
58 | + } | ||
59 | + | ||
60 | + public int getId() { | ||
61 | + return id; | ||
62 | + } | ||
63 | + | ||
64 | + public static IRDot[] getIRDots(IRLight[] lights) { | ||
65 | + IRDot[] dots = new IRDot[lights.length]; | ||
66 | + for (int i = 0; i < lights.length; i++) { | ||
67 | + dots[i] = lights[i] == null ? null : new IRDot(i, lights[i]); | ||
68 | + } | ||
69 | + return dots; | ||
70 | + } | ||
71 | + | ||
72 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/Wiimote.java
0 → 100644
@@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
1 | +package org.mote.wiimote.whiteboard.ds; | ||
2 | + | ||
3 | +import wiiremotej.WiiRemote; | ||
4 | + | ||
5 | +public class Wiimote { | ||
6 | + private final WiiRemote wiiremote; | ||
7 | + private final String address; | ||
8 | + private final int id; | ||
9 | + public Wiimote(WiiRemote wiiremote, String address, int id) { | ||
10 | + this.wiiremote = wiiremote; | ||
11 | + this.address = address; | ||
12 | + this.id = id; | ||
13 | + } | ||
14 | + public WiiRemote getWiiRemote() { | ||
15 | + return wiiremote; | ||
16 | + } | ||
17 | + public String getAddress() { | ||
18 | + return address; | ||
19 | + } | ||
20 | + public int getId() { | ||
21 | + return id; | ||
22 | + } | ||
23 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/Wiimote.java~
0 → 100644
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.ds; | ||
27 | + | ||
28 | +import wiiremotej.WiiRemote; | ||
29 | + | ||
30 | +public class Wiimote { | ||
31 | + private final WiiRemote wiiremote; | ||
32 | + private final String address; | ||
33 | + private final int id; | ||
34 | + public Wiimote(WiiRemote wiiremote, String address, int id) { | ||
35 | + this.wiiremote = wiiremote; | ||
36 | + this.address = address; | ||
37 | + this.id = id; | ||
38 | + } | ||
39 | + public WiiRemote getWiiRemote() { | ||
40 | + return wiiremote; | ||
41 | + } | ||
42 | + public String getAddress() { | ||
43 | + return address; | ||
44 | + } | ||
45 | + public int getId() { | ||
46 | + return id; | ||
47 | + } | ||
48 | +} | ||
0 | \ No newline at end of file | 49 | \ No newline at end of file |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/AboutWindow.java
0 → 100644
@@ -0,0 +1,72 @@ | @@ -0,0 +1,72 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.BorderLayout; | ||
4 | +import java.awt.Font; | ||
5 | +import java.net.URL; | ||
6 | + | ||
7 | +import javax.swing.JDialog; | ||
8 | +import javax.swing.JEditorPane; | ||
9 | +import javax.swing.JLabel; | ||
10 | +import javax.swing.JPanel; | ||
11 | +import javax.swing.JScrollPane; | ||
12 | +import javax.swing.event.HyperlinkEvent; | ||
13 | +import javax.swing.event.HyperlinkListener; | ||
14 | + | ||
15 | +import net.miginfocom.swing.MigLayout; | ||
16 | + | ||
17 | +import org.jdesktop.application.Action; | ||
18 | +import org.jdesktop.application.Application; | ||
19 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
20 | +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch; | ||
21 | +import org.mote.wiimote.whiteboard.util.Util; | ||
22 | + | ||
23 | +@SuppressWarnings("serial") | ||
24 | +public class AboutWindow extends JDialog implements HyperlinkListener { | ||
25 | + | ||
26 | + public AboutWindow() { | ||
27 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame()); | ||
28 | + if (!Util.INSIDE_APP_BUNDLE) { | ||
29 | + setName("aboutWindow"); | ||
30 | + setLayout(new BorderLayout()); | ||
31 | + final JPanel appPane = Util.newComponent(JPanel.class, "appPane"); | ||
32 | + add(appPane, BorderLayout.NORTH); | ||
33 | + appPane.setLayout(new MigLayout("insets i", "[center|center]")); | ||
34 | + | ||
35 | + JLabel appLabel = new JLabel(String.format("%s %s", WiimoteWhiteboard.getProperty("id"), WiimoteWhiteboard.getProperty("version"))); | ||
36 | + appLabel.setFont(appLabel.getFont().deriveFont(Font.BOLD, 14f)); | ||
37 | + JLabel crLabel = new JLabel(Util.getResourceMap(AboutWindow.class).getString("copyRight", WiimoteWhiteboard.getProperty("year"), WiimoteWhiteboard.getProperty("author"))); | ||
38 | + crLabel.setFont(appLabel.getFont().deriveFont(10f)); | ||
39 | + | ||
40 | + appPane.add(appLabel, "flowy, split 2"); | ||
41 | + appPane.add(crLabel, ""); | ||
42 | + appPane.add(new JLabel(Util.getResourceMap(WiimoteWhiteboard.class).getImageIcon("icon")), "flowx, wrap"); | ||
43 | + | ||
44 | + try { | ||
45 | + | ||
46 | + JEditorPane tp = Util.newComponent(JEditorPane.class, "infoPane"); | ||
47 | + tp.addHyperlinkListener(this); | ||
48 | + | ||
49 | + add(new JScrollPane(tp), BorderLayout.CENTER); | ||
50 | + | ||
51 | + Util.getResourceMap(AboutWindow.class).injectComponents(this); | ||
52 | + | ||
53 | + setResizable(false); | ||
54 | + Util.placeDialogWindow(this, 295, 348); | ||
55 | + } catch (Exception e) { | ||
56 | + e.printStackTrace(); | ||
57 | + } | ||
58 | + } | ||
59 | + } | ||
60 | + | ||
61 | + public void hyperlinkUpdate(HyperlinkEvent e) { | ||
62 | + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { | ||
63 | + | ||
64 | + } | ||
65 | + } | ||
66 | + | ||
67 | + @Action | ||
68 | + public void about() { | ||
69 | + setVisible(true); | ||
70 | + } | ||
71 | + | ||
72 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/AboutWindow.java~
0 → 100644
@@ -0,0 +1,72 @@ | @@ -0,0 +1,72 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.BorderLayout; | ||
4 | +import java.awt.Font; | ||
5 | +import java.net.URL; | ||
6 | + | ||
7 | +import javax.swing.JDialog; | ||
8 | +import javax.swing.JEditorPane; | ||
9 | +import javax.swing.JLabel; | ||
10 | +import javax.swing.JPanel; | ||
11 | +import javax.swing.JScrollPane; | ||
12 | +import javax.swing.event.HyperlinkEvent; | ||
13 | +import javax.swing.event.HyperlinkListener; | ||
14 | + | ||
15 | +import net.miginfocom.swing.MigLayout; | ||
16 | + | ||
17 | +import org.jdesktop.application.Action; | ||
18 | +import org.jdesktop.application.Application; | ||
19 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
20 | +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch; | ||
21 | +import org.mote.wiimote.whiteboard.util.Util; | ||
22 | + | ||
23 | +@SuppressWarnings("serial") | ||
24 | +public class AboutWindow extends JDialog implements HyperlinkListener { | ||
25 | + | ||
26 | + public AboutWindow() { | ||
27 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame()); | ||
28 | + if (!Util.INSIDE_APP_BUNDLE) { | ||
29 | + setName("aboutWindow"); | ||
30 | + setLayout(new BorderLayout()); | ||
31 | + final JPanel appPane = Util.newComponent(JPanel.class, "appPane"); | ||
32 | + add(appPane, BorderLayout.NORTH); | ||
33 | + appPane.setLayout(new MigLayout("insets i", "[center|center]")); | ||
34 | + | ||
35 | + JLabel appLabel = new JLabel(String.format("%s %s", WiimoteWhiteboard.getProperty("id"), WiimoteWhiteboard.getProperty("version"))); | ||
36 | + appLabel.setFont(appLabel.getFont().deriveFont(Font.BOLD, 14f)); | ||
37 | + JLabel crLabel = new JLabel(Util.getResourceMap(AboutWindow.class).getString("copyRight", WiimoteWhiteboard.getProperty("year"), WiimoteWhiteboard.getProperty("author"))); | ||
38 | + crLabel.setFont(appLabel.getFont().deriveFont(10f)); | ||
39 | + | ||
40 | + appPane.add(appLabel, "flowy, split 2"); | ||
41 | + appPane.add(crLabel, ""); | ||
42 | + appPane.add(new JLabel(Util.getResourceMap(WiimoteWhiteboard.class).getImageIcon("icon")), "flowx, wrap"); | ||
43 | + | ||
44 | + try { | ||
45 | + URL url = AboutWindow.class.getResource("resources/Credits.html"); | ||
46 | + JEditorPane tp = Util.newComponent(JEditorPane.class, "infoPane"); | ||
47 | + tp.addHyperlinkListener(this); | ||
48 | + tp.setPage(url); | ||
49 | + add(new JScrollPane(tp), BorderLayout.CENTER); | ||
50 | + | ||
51 | + Util.getResourceMap(AboutWindow.class).injectComponents(this); | ||
52 | + | ||
53 | + setResizable(false); | ||
54 | + Util.placeDialogWindow(this, 295, 348); | ||
55 | + } catch (Exception e) { | ||
56 | + e.printStackTrace(); | ||
57 | + } | ||
58 | + } | ||
59 | + } | ||
60 | + | ||
61 | + public void hyperlinkUpdate(HyperlinkEvent e) { | ||
62 | + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { | ||
63 | + BareBonesBrowserLaunch.openURL(e.getURL().toString()); | ||
64 | + } | ||
65 | + } | ||
66 | + | ||
67 | + @Action | ||
68 | + public void about() { | ||
69 | + setVisible(true); | ||
70 | + } | ||
71 | + | ||
72 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CalibrationInfoWindow.java
0 → 100644
@@ -0,0 +1,267 @@ | @@ -0,0 +1,267 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Color; | ||
4 | +import java.awt.Graphics; | ||
5 | +import java.awt.Graphics2D; | ||
6 | +import java.awt.Point; | ||
7 | +import java.awt.RenderingHints; | ||
8 | +import java.awt.SystemColor; | ||
9 | +import java.awt.event.ComponentAdapter; | ||
10 | +import java.awt.event.ComponentEvent; | ||
11 | +import java.awt.event.KeyAdapter; | ||
12 | +import java.awt.event.KeyEvent; | ||
13 | +import java.util.Map; | ||
14 | +import java.util.Timer; | ||
15 | +import java.util.TimerTask; | ||
16 | + | ||
17 | +import javax.swing.BorderFactory; | ||
18 | +import javax.swing.JDialog; | ||
19 | +import javax.swing.JLabel; | ||
20 | +import javax.swing.JPanel; | ||
21 | +import javax.swing.JProgressBar; | ||
22 | + | ||
23 | +import net.miginfocom.swing.MigLayout; | ||
24 | + | ||
25 | +import org.jdesktop.application.Action; | ||
26 | +import org.jdesktop.application.Application; | ||
27 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler; | ||
28 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
29 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
30 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
31 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
32 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener; | ||
33 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
34 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
35 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
36 | +import org.mote.wiimote.whiteboard.util.Util; | ||
37 | + | ||
38 | +@SuppressWarnings("serial") | ||
39 | +public class CalibrationInfoWindow extends JDialog implements CalibrationEventListener, WiimoteDataListener { | ||
40 | + | ||
41 | + private static class WiimoteWrapper { | ||
42 | + @SuppressWarnings("unused") | ||
43 | + private int idx; | ||
44 | + private JPanel panel; | ||
45 | + private WiimoteIcon icon; | ||
46 | + private JProgressBar trackingUtility; | ||
47 | + private Double d[]; | ||
48 | + private IRDot[] lights = new IRDot[4]; | ||
49 | + private void setVisible(boolean visible) { | ||
50 | + panel.setVisible(visible); | ||
51 | + icon.setVisible(visible); | ||
52 | + trackingUtility.setVisible(visible); | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + private static final long REPAINT_FREQ = 1000 / 25; | ||
57 | + | ||
58 | + private static final Color CALIBRATED_COLOR = SystemColor.textHighlight; | ||
59 | + private static final Color TRACKING_COLOR = SystemColor.text; | ||
60 | + | ||
61 | + private static final Color COLORS[] = {Color.blue, Color.red, Color.green, Color.orange, Color.black, Color.cyan, Color.magenta, Color.pink}; | ||
62 | + | ||
63 | + private WiimoteWrapper ww[] = new WiimoteWrapper[WWPreferences.WIIMOTES]; | ||
64 | + private WiimoteCalibration calibration; | ||
65 | + private WiimoteDataHandler dh; | ||
66 | + private boolean calibrated = false; | ||
67 | + | ||
68 | +// private Matrix F; | ||
69 | + | ||
70 | + | ||
71 | + public CalibrationInfoWindow(WiimoteCalibration calibration, WiimoteDataHandler dh) { | ||
72 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CalibrationInfoWindow.class).getString("info.Action.text")); | ||
73 | + getRootPane().putClientProperty("Window.style", "small"); | ||
74 | + this.calibration = calibration; | ||
75 | + this.dh = dh; | ||
76 | + calibration.addCalibrationEventListener(this); | ||
77 | + dh.addWiimoteDataListener(this); | ||
78 | + setLayout(new MigLayout("hidemode 3")); | ||
79 | + // info labels | ||
80 | + final JLabel taLabel = Util.newComponent(JLabel.class, "trackingAreaLabel"); | ||
81 | + final JLabel csLabel = Util.newComponent(JLabel.class, "calibratedScreenLabel"); | ||
82 | + taLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
83 | + csLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
84 | + taLabel.setBackground(TRACKING_COLOR); | ||
85 | + csLabel.setBackground(CALIBRATED_COLOR); | ||
86 | + taLabel.setForeground(SystemColor.textText); | ||
87 | + csLabel.setForeground(SystemColor.textHighlightText); | ||
88 | + add(taLabel, "sg 1, split, span, growx, pushx"); | ||
89 | + add(csLabel, "sg 1, gapbefore 0, growx, pushx, wrap"); | ||
90 | + | ||
91 | + for (int i = 0; i < ww.length; i++) { | ||
92 | + ww[i] = new WiimoteWrapper(); | ||
93 | + ww[i].idx = i; | ||
94 | + ww[i].icon = new WiimoteIcon(i+1); | ||
95 | + ww[i].icon.displayConnected(true); | ||
96 | + add(ww[i].panel = new InfoPanel(ww[i]), "flowy, w 400, h 300, grow, push"); | ||
97 | + add(ww[i].icon, "cell "+i+" 1, growx, pushx"); | ||
98 | + add(ww[i].trackingUtility = Util.newComponent(JProgressBar.class, "trackingUtility"), "cell "+i+" 1, growx, pushx"); | ||
99 | + ww[i].setVisible(i == 0); | ||
100 | + } | ||
101 | + | ||
102 | + addKeyListener(new KeyAdapter() { | ||
103 | + @Override | ||
104 | + public void keyPressed(KeyEvent e) { | ||
105 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
106 | + setVisible(false); | ||
107 | + } | ||
108 | + } | ||
109 | + }); | ||
110 | + | ||
111 | + addComponentListener(new ComponentAdapter() { | ||
112 | + @Override | ||
113 | + public void componentMoved(ComponentEvent e) { | ||
114 | + componentResized(null); | ||
115 | + } | ||
116 | + @Override | ||
117 | + public void componentResized(ComponentEvent e) { | ||
118 | + repaintPanels(); | ||
119 | + } | ||
120 | + }); | ||
121 | + | ||
122 | + | ||
123 | + Util.getResourceMap(CalibrationInfoWindow.class).injectComponents(this); | ||
124 | + pack(); | ||
125 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
126 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
127 | + } | ||
128 | + | ||
129 | + private class UpdateTask extends TimerTask { | ||
130 | + @Override | ||
131 | + public void run() { | ||
132 | + if (isVisible()) { | ||
133 | + repaintPanels(); | ||
134 | + } | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + private void repaintPanels() { | ||
139 | + for (WiimoteWrapper wrapper : ww) { | ||
140 | + if (wrapper.panel.isVisible()) | ||
141 | + wrapper.panel.repaint(); | ||
142 | + } | ||
143 | + } | ||
144 | + | ||
145 | + @Action(enabledProperty="calibrated") | ||
146 | + public void info() { | ||
147 | + setVisible(true); | ||
148 | + } | ||
149 | + | ||
150 | + public boolean isCalibrated() { | ||
151 | + return calibrated; | ||
152 | + } | ||
153 | + | ||
154 | + private void updateCalibrated() { | ||
155 | + final boolean old = calibrated; | ||
156 | + calibrated = dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes()); | ||
157 | + firePropertyChange("calibrated", old, calibrated); | ||
158 | + } | ||
159 | + | ||
160 | + public void calibrationEvent(CalibrationEvent e) { | ||
161 | + switch (e) { | ||
162 | + case LOADED: | ||
163 | + update(); | ||
164 | + case FINISHED: | ||
165 | + update(); | ||
166 | + break; | ||
167 | + case SCREEN_CHANGED: | ||
168 | + case STARTED: | ||
169 | + case ABORTED: | ||
170 | + case SAVED: | ||
171 | + } | ||
172 | + updateCalibrated(); | ||
173 | + if (!isCalibrated()) | ||
174 | + setVisible(false); | ||
175 | + } | ||
176 | + | ||
177 | + public void batteryLevel(Wiimote wiimote, double level) {} | ||
178 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
179 | + ww[wiimote.getId()-1].lights = lights; | ||
180 | + } | ||
181 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {} | ||
182 | + public void wiimoteConnected(Wiimote wiimote) { | ||
183 | + update(); | ||
184 | + updateCalibrated(); | ||
185 | + } | ||
186 | + public void wiimoteDisconnected(Wiimote wiimote) {} | ||
187 | + | ||
188 | + private int r(double d) { | ||
189 | + return (int)Math.round(d); | ||
190 | + } | ||
191 | + | ||
192 | + private void update() { | ||
193 | + Map<String, Double[]> finals = calibration.getFinals(); | ||
194 | + | ||
195 | + | ||
196 | + | ||
197 | + for (Wiimote wiimote : dh.getConnectedWiimotes()) { | ||
198 | + WiimoteWrapper w = ww[wiimote.getId()-1]; | ||
199 | + if (!calibration.isCalibrated(wiimote)) continue; | ||
200 | + | ||
201 | + w.d = finals.get(wiimote.getAddress()); | ||
202 | + | ||
203 | + double x0 = w.d[0]*1024, y0 = w.d[1]*768; | ||
204 | + double x1 = w.d[2]*1024, y1 = w.d[3]*768; | ||
205 | + double x3 = w.d[4]*1024, y3 = w.d[5]*768; | ||
206 | + double x2 = w.d[6]*1024, y2 = w.d[7]*768; | ||
207 | + double idealArea = 0.8 * 1024 * 0.8 * 768; | ||
208 | + double calibratedArea = 0.5 * (Math.abs( | ||
209 | + (x1 - x2) * (y0 - y3) - (x0 - x3) * (y1 - y2) | ||
210 | + )); | ||
211 | + | ||
212 | + w.trackingUtility.setValue(r(calibratedArea)); | ||
213 | + w.trackingUtility.setString(Util.getResourceMap(CalibrationInfoWindow.class).getString("trackingUtilString", 100 * (calibratedArea / idealArea))); | ||
214 | + | ||
215 | + if (!w.panel.isVisible()) { | ||
216 | + w.setVisible(true); | ||
217 | + pack(); | ||
218 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
219 | + } | ||
220 | + } | ||
221 | + repaintPanels(); | ||
222 | + } | ||
223 | + | ||
224 | + private class InfoPanel extends JPanel { | ||
225 | + private static final int DIAMETER = 6; | ||
226 | + private WiimoteWrapper wrapper; | ||
227 | + public InfoPanel(WiimoteWrapper wrapper) { | ||
228 | + this.wrapper = wrapper; | ||
229 | + setLayout(null); | ||
230 | + setOpaque(true); | ||
231 | + setBackground(TRACKING_COLOR); | ||
232 | + setBorder(BorderFactory.createLineBorder(SystemColor.lightGray)); | ||
233 | + } | ||
234 | + @Override | ||
235 | + protected void paintComponent(Graphics g) { | ||
236 | + super.paintComponent(g); | ||
237 | + if (wrapper.d != null) { | ||
238 | + Graphics2D g2d = (Graphics2D)g; | ||
239 | + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
240 | + final int w = getWidth(); | ||
241 | + final int h = getHeight(); | ||
242 | + int x[] = new int[5], y[] = new int[5]; | ||
243 | + for (int i = 0; i < 4; i++) { | ||
244 | + x[i] = r(wrapper.d[2*i]*w); | ||
245 | + y[i] = r(h-wrapper.d[2*i+1]*h); | ||
246 | + } | ||
247 | + x[4] = x[0]; y[4] = y[0]; | ||
248 | + | ||
249 | + g2d.setColor(CALIBRATED_COLOR); | ||
250 | + g2d.fillPolygon(x, y, 5); | ||
251 | + | ||
252 | + | ||
253 | + for (int i = 0; i < 4; i++) { | ||
254 | + IRDot dot = wrapper.lights[i]; | ||
255 | + if (dot != null) { | ||
256 | + g2d.setColor(COLORS[i]); | ||
257 | + | ||
258 | + g2d.fillOval(r(w*dot.x)-DIAMETER/2, r(h-h*dot.y)-DIAMETER/2, DIAMETER, DIAMETER); | ||
259 | + | ||
260 | + } | ||
261 | + } | ||
262 | + } | ||
263 | + } | ||
264 | + } | ||
265 | + | ||
266 | + | ||
267 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CalibrationInfoWindow.java~
0 → 100644
@@ -0,0 +1,267 @@ | @@ -0,0 +1,267 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Color; | ||
4 | +import java.awt.Graphics; | ||
5 | +import java.awt.Graphics2D; | ||
6 | +import java.awt.Point; | ||
7 | +import java.awt.RenderingHints; | ||
8 | +import java.awt.SystemColor; | ||
9 | +import java.awt.event.ComponentAdapter; | ||
10 | +import java.awt.event.ComponentEvent; | ||
11 | +import java.awt.event.KeyAdapter; | ||
12 | +import java.awt.event.KeyEvent; | ||
13 | +import java.util.Map; | ||
14 | +import java.util.Timer; | ||
15 | +import java.util.TimerTask; | ||
16 | + | ||
17 | +import javax.swing.BorderFactory; | ||
18 | +import javax.swing.JDialog; | ||
19 | +import javax.swing.JLabel; | ||
20 | +import javax.swing.JPanel; | ||
21 | +import javax.swing.JProgressBar; | ||
22 | + | ||
23 | +import net.miginfocom.swing.MigLayout; | ||
24 | + | ||
25 | +import org.jdesktop.application.Action; | ||
26 | +import org.jdesktop.application.Application; | ||
27 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler; | ||
28 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
29 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
30 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
31 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
32 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener; | ||
33 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
34 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
35 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
36 | +import org.mote.wiimote.whiteboard.util.Util; | ||
37 | + | ||
38 | +@SuppressWarnings("serial") | ||
39 | +public class CalibrationInfoWindow extends JDialog implements CalibrationEventListener, WiimoteDataListener { | ||
40 | + | ||
41 | + private static class WiimoteWrapper { | ||
42 | + @SuppressWarnings("unused") | ||
43 | + private int idx; | ||
44 | + private JPanel panel; | ||
45 | + private WiimoteIcon icon; | ||
46 | + private JProgressBar trackingUtility; | ||
47 | + private Double d[]; | ||
48 | + private IRDot[] lights = new IRDot[4]; | ||
49 | + private void setVisible(boolean visible) { | ||
50 | + panel.setVisible(visible); | ||
51 | + icon.setVisible(visible); | ||
52 | + trackingUtility.setVisible(visible); | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + private static final long REPAINT_FREQ = 1000 / 25; | ||
57 | + | ||
58 | + private static final Color CALIBRATED_COLOR = SystemColor.textHighlight; | ||
59 | + private static final Color TRACKING_COLOR = SystemColor.text; | ||
60 | + | ||
61 | + private static final Color COLORS[] = {Color.blue, Color.red, Color.green, Color.orange, Color.black, Color.cyan, Color.magenta, Color.pink}; | ||
62 | + | ||
63 | + private WiimoteWrapper ww[] = new WiimoteWrapper[WWPreferences.WIIMOTES]; | ||
64 | + private WiimoteCalibration calibration; | ||
65 | + private WiimoteDataHandler dh; | ||
66 | + private boolean calibrated = false; | ||
67 | + | ||
68 | +// private Matrix F; | ||
69 | + | ||
70 | + | ||
71 | + public CalibrationInfoWindow(WiimoteCalibration calibration, WiimoteDataHandler dh) { | ||
72 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CalibrationInfoWindow.class).getString("info.Action.text")); | ||
73 | + getRootPane().putClientProperty("Window.style", "small"); | ||
74 | + this.calibration = calibration; | ||
75 | + this.dh = dh; | ||
76 | + calibration.addCalibrationEventListener(this); | ||
77 | + dh.addWiimoteDataListener(this); | ||
78 | + setLayout(new MigLayout("hidemode 3")); | ||
79 | + // info labels | ||
80 | + final JLabel taLabel = Util.newComponent(JLabel.class, "trackingAreaLabel"); | ||
81 | + final JLabel csLabel = Util.newComponent(JLabel.class, "calibratedScreenLabel"); | ||
82 | + taLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
83 | + csLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
84 | + taLabel.setBackground(TRACKING_COLOR); | ||
85 | + csLabel.setBackground(CALIBRATED_COLOR); | ||
86 | + taLabel.setForeground(SystemColor.textText); | ||
87 | + csLabel.setForeground(SystemColor.textHighlightText); | ||
88 | + add(taLabel, "sg 1, split, span, growx, pushx"); | ||
89 | + add(csLabel, "sg 1, gapbefore 0, growx, pushx, wrap"); | ||
90 | + | ||
91 | + for (int i = 0; i < ww.length; i++) { | ||
92 | + ww[i] = new WiimoteWrapper(); | ||
93 | + ww[i].idx = i; | ||
94 | + ww[i].icon = new WiimoteIcon(i+1); | ||
95 | + ww[i].icon.displayConnected(true); | ||
96 | + add(ww[i].panel = new InfoPanel(ww[i]), "flowy, w 400, h 300, grow, push"); | ||
97 | + add(ww[i].icon, "cell "+i+" 1, growx, pushx"); | ||
98 | + add(ww[i].trackingUtility = Util.newComponent(JProgressBar.class, "trackingUtility"), "cell "+i+" 1, growx, pushx"); | ||
99 | + ww[i].setVisible(i == 0); | ||
100 | + } | ||
101 | + | ||
102 | + addKeyListener(new KeyAdapter() { | ||
103 | + @Override | ||
104 | + public void keyPressed(KeyEvent e) { | ||
105 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
106 | + setVisible(false); | ||
107 | + } | ||
108 | + } | ||
109 | + }); | ||
110 | + | ||
111 | + addComponentListener(new ComponentAdapter() { | ||
112 | + @Override | ||
113 | + public void componentMoved(ComponentEvent e) { | ||
114 | + componentResized(null); | ||
115 | + } | ||
116 | + @Override | ||
117 | + public void componentResized(ComponentEvent e) { | ||
118 | + repaintPanels(); | ||
119 | + } | ||
120 | + }); | ||
121 | + | ||
122 | + | ||
123 | + Util.getResourceMap(CalibrationInfoWindow.class).injectComponents(this); | ||
124 | + pack(); | ||
125 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
126 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
127 | + } | ||
128 | + | ||
129 | + private class UpdateTask extends TimerTask { | ||
130 | + @Override | ||
131 | + public void run() { | ||
132 | + if (isVisible()) { | ||
133 | + repaintPanels(); | ||
134 | + } | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + private void repaintPanels() { | ||
139 | + for (WiimoteWrapper wrapper : ww) { | ||
140 | + if (wrapper.panel.isVisible()) | ||
141 | + wrapper.panel.repaint(); | ||
142 | + } | ||
143 | + } | ||
144 | + | ||
145 | + @Action(enabledProperty="calibrated") | ||
146 | + public void info() { | ||
147 | + setVisible(true); | ||
148 | + } | ||
149 | + | ||
150 | + public boolean isCalibrated() { | ||
151 | + return calibrated; | ||
152 | + } | ||
153 | + | ||
154 | + private void updateCalibrated() { | ||
155 | + final boolean old = calibrated; | ||
156 | + calibrated = dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes()); | ||
157 | + firePropertyChange("calibrated", old, calibrated); | ||
158 | + } | ||
159 | + | ||
160 | + public void calibrationEvent(CalibrationEvent e) { | ||
161 | + switch (e) { | ||
162 | + case LOADED: | ||
163 | + update(); | ||
164 | + case FINISHED: | ||
165 | + update(); | ||
166 | + break; | ||
167 | + case SCREEN_CHANGED: | ||
168 | + case STARTED: | ||
169 | + case ABORTED: | ||
170 | + case SAVED: | ||
171 | + } | ||
172 | + updateCalibrated(); | ||
173 | + if (!isCalibrated()) | ||
174 | + setVisible(false); | ||
175 | + } | ||
176 | + | ||
177 | + public void batteryLevel(Wiimote wiimote, double level) {} | ||
178 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
179 | + ww[wiimote.getId()-1].lights = lights; | ||
180 | + } | ||
181 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {} | ||
182 | + public void wiimoteConnected(Wiimote wiimote) { | ||
183 | + update(); | ||
184 | + updateCalibrated(); | ||
185 | + } | ||
186 | + public void wiimoteDisconnected(Wiimote wiimote) {} | ||
187 | + | ||
188 | + private int r(double d) { | ||
189 | + return (int)Math.round(d); | ||
190 | + } | ||
191 | + | ||
192 | + private void update() { | ||
193 | + Map<String, Double[]> finals = calibration.getFinals(); | ||
194 | + | ||
195 | + | ||
196 | + | ||
197 | + for (Wiimote wiimote : dh.getConnectedWiimotes()) { | ||
198 | + WiimoteWrapper w = ww[wiimote.getId()-1]; | ||
199 | + if (!calibration.isCalibrated(wiimote)) continue; | ||
200 | + | ||
201 | + w.d = finals.get(wiimote.getAddress()); | ||
202 | + | ||
203 | + double x0 = w.d[0]*1024, y0 = w.d[1]*768; | ||
204 | + double x1 = w.d[2]*1024, y1 = w.d[3]*768; | ||
205 | + double x3 = w.d[4]*1024, y3 = w.d[5]*768; | ||
206 | + double x2 = w.d[6]*1024, y2 = w.d[7]*768; | ||
207 | + double idealArea = 0.8 * 1024 * 0.8 * 768; | ||
208 | + double calibratedArea = 0.5 * (Math.abs( | ||
209 | + (x1 - x2) * (y0 - y3) - (x0 - x3) * (y1 - y2) | ||
210 | + )); | ||
211 | + | ||
212 | + w.trackingUtility.setValue(r(calibratedArea)); | ||
213 | + w.trackingUtility.setString(Util.getResourceMap(CalibrationInfoWindow.class).getString("trackingUtilString", 100 * (calibratedArea / idealArea))); | ||
214 | + | ||
215 | + if (!w.panel.isVisible()) { | ||
216 | + w.setVisible(true); | ||
217 | + pack(); | ||
218 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
219 | + } | ||
220 | + } | ||
221 | + repaintPanels(); | ||
222 | + } | ||
223 | + | ||
224 | + private class InfoPanel extends JPanel { | ||
225 | + private static final int DIAMETER = 6; | ||
226 | + private WiimoteWrapper wrapper; | ||
227 | + public InfoPanel(WiimoteWrapper wrapper) { | ||
228 | + this.wrapper = wrapper; | ||
229 | + setLayout(null); | ||
230 | + setOpaque(true); | ||
231 | + setBackground(TRACKING_COLOR); | ||
232 | + setBorder(BorderFactory.createLineBorder(SystemColor.lightGray)); | ||
233 | + } | ||
234 | + @Override | ||
235 | + protected void paintComponent(Graphics g) { | ||
236 | + super.paintComponent(g); | ||
237 | + if (wrapper.d != null) { | ||
238 | + Graphics2D g2d = (Graphics2D)g; | ||
239 | + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
240 | + final int w = getWidth(); | ||
241 | + final int h = getHeight(); | ||
242 | + int x[] = new int[5], y[] = new int[5]; | ||
243 | + for (int i = 0; i < 4; i++) { | ||
244 | + x[i] = r(wrapper.d[2*i]*w); | ||
245 | + y[i] = r(h-wrapper.d[2*i+1]*h); | ||
246 | + } | ||
247 | + x[4] = x[0]; y[4] = y[0]; | ||
248 | + | ||
249 | + g2d.setColor(CALIBRATED_COLOR); | ||
250 | + g2d.fillPolygon(x, y, 5); | ||
251 | + | ||
252 | + | ||
253 | + for (int i = 0; i < 4; i++) { | ||
254 | + IRDot dot = wrapper.lights[i]; | ||
255 | + if (dot != null) { | ||
256 | + g2d.setColor(COLORS[i]); | ||
257 | + | ||
258 | + g2d.fillOval(r(w*dot.x)-DIAMETER/2, r(h-h*dot.y)-DIAMETER/2, DIAMETER, DIAMETER); | ||
259 | + | ||
260 | + } | ||
261 | + } | ||
262 | + } | ||
263 | + } | ||
264 | + } | ||
265 | + | ||
266 | + | ||
267 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CameraMonitor.java
0 → 100644
@@ -0,0 +1,103 @@ | @@ -0,0 +1,103 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Point; | ||
4 | +import java.awt.SystemColor; | ||
5 | +import java.awt.event.KeyAdapter; | ||
6 | +import java.awt.event.KeyEvent; | ||
7 | +import java.util.Map; | ||
8 | +import java.util.Timer; | ||
9 | +import java.util.TimerTask; | ||
10 | + | ||
11 | +import javax.swing.BorderFactory; | ||
12 | +import javax.swing.JDialog; | ||
13 | +import javax.swing.JPanel; | ||
14 | + | ||
15 | +import net.miginfocom.swing.MigLayout; | ||
16 | + | ||
17 | +import org.jdesktop.application.Action; | ||
18 | +import org.jdesktop.application.Application; | ||
19 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler; | ||
20 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
21 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
22 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
23 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
24 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
25 | +import org.mote.wiimote.whiteboard.util.Util; | ||
26 | + | ||
27 | +@SuppressWarnings("serial") | ||
28 | +public class CameraMonitor extends JDialog implements WiimoteDataListener { | ||
29 | + | ||
30 | + private static final long REPAINT_FREQ = 1000 / 25; | ||
31 | + | ||
32 | + private JPanel canvas; | ||
33 | + private IRDot[][] lights = new IRDot[WWPreferences.WIIMOTES+1][4]; | ||
34 | + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4]; | ||
35 | + | ||
36 | + public CameraMonitor(WiimoteDataHandler dh) { | ||
37 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CameraMonitor.class).getString("monitor.Action.text")); | ||
38 | + getRootPane().putClientProperty("Window.style", "small"); | ||
39 | + setLayout(new MigLayout()); | ||
40 | + | ||
41 | + dh.addWiimoteDataListener(this); | ||
42 | + | ||
43 | + canvas = new JPanel(null, true); | ||
44 | + canvas.setOpaque(true); | ||
45 | + canvas.setBorder(BorderFactory.createLineBorder(SystemColor.inactiveCaptionBorder)); | ||
46 | + add(canvas, "w 50sp, h 50sp, grow, push"); | ||
47 | + | ||
48 | + addKeyListener(new KeyAdapter() { | ||
49 | + @Override | ||
50 | + public void keyPressed(KeyEvent e) { | ||
51 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
52 | + setVisible(false); | ||
53 | + } | ||
54 | + } | ||
55 | + }); | ||
56 | + | ||
57 | + pack(); | ||
58 | + setLocationRelativeTo(null); | ||
59 | + | ||
60 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
61 | + } | ||
62 | + | ||
63 | + @Action | ||
64 | + public void monitor() { | ||
65 | + setVisible(true); | ||
66 | + } | ||
67 | + | ||
68 | + private class UpdateTask extends TimerTask { | ||
69 | + @Override | ||
70 | + public void run() { | ||
71 | + if (isVisible()) { | ||
72 | + for (int i = 1; i <= WWPreferences.WIIMOTES; i++) | ||
73 | + for (int j = 0; j < 4; j++) { | ||
74 | + if (labels[i][j] != null) | ||
75 | + labels[i][j].update(); | ||
76 | + } | ||
77 | + } | ||
78 | + } | ||
79 | + } | ||
80 | + | ||
81 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
82 | + this.lights[wiimote.getId()] = lights; | ||
83 | + } | ||
84 | + | ||
85 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
86 | + } | ||
87 | + | ||
88 | + public void batteryLevel(Wiimote wiimote, double level) { | ||
89 | + } | ||
90 | + | ||
91 | + public void wiimoteConnected(Wiimote wiimote) { | ||
92 | + for (int i = 0; i < 4; i++) | ||
93 | + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1)); | ||
94 | + } | ||
95 | + | ||
96 | + public void wiimoteDisconnected(Wiimote wiimote) { | ||
97 | + for (int i = 0; i < 4; i++) { | ||
98 | + canvas.remove(labels[wiimote.getId()][i]); | ||
99 | + labels[wiimote.getId()][i] = null; | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CameraMonitor.java~
0 → 100644
@@ -0,0 +1,128 @@ | @@ -0,0 +1,128 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import java.awt.Point; | ||
29 | +import java.awt.SystemColor; | ||
30 | +import java.awt.event.KeyAdapter; | ||
31 | +import java.awt.event.KeyEvent; | ||
32 | +import java.util.Map; | ||
33 | +import java.util.Timer; | ||
34 | +import java.util.TimerTask; | ||
35 | + | ||
36 | +import javax.swing.BorderFactory; | ||
37 | +import javax.swing.JDialog; | ||
38 | +import javax.swing.JPanel; | ||
39 | + | ||
40 | +import net.miginfocom.swing.MigLayout; | ||
41 | + | ||
42 | +import org.jdesktop.application.Action; | ||
43 | +import org.jdesktop.application.Application; | ||
44 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler; | ||
45 | +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard; | ||
46 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
47 | +import org.uweschmidt.wiimote.whiteboard.ds.IRDot; | ||
48 | +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote; | ||
49 | +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences; | ||
50 | +import org.uweschmidt.wiimote.whiteboard.util.Util; | ||
51 | + | ||
52 | +@SuppressWarnings("serial") | ||
53 | +public class CameraMonitor extends JDialog implements WiimoteDataListener { | ||
54 | + | ||
55 | + private static final long REPAINT_FREQ = 1000 / 25; | ||
56 | + | ||
57 | + private JPanel canvas; | ||
58 | + private IRDot[][] lights = new IRDot[WWPreferences.WIIMOTES+1][4]; | ||
59 | + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4]; | ||
60 | + | ||
61 | + public CameraMonitor(WiimoteDataHandler dh) { | ||
62 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CameraMonitor.class).getString("monitor.Action.text")); | ||
63 | + getRootPane().putClientProperty("Window.style", "small"); | ||
64 | + setLayout(new MigLayout()); | ||
65 | + | ||
66 | + dh.addWiimoteDataListener(this); | ||
67 | + | ||
68 | + canvas = new JPanel(null, true); | ||
69 | + canvas.setOpaque(true); | ||
70 | + canvas.setBorder(BorderFactory.createLineBorder(SystemColor.inactiveCaptionBorder)); | ||
71 | + add(canvas, "w 50sp, h 50sp, grow, push"); | ||
72 | + | ||
73 | + addKeyListener(new KeyAdapter() { | ||
74 | + @Override | ||
75 | + public void keyPressed(KeyEvent e) { | ||
76 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
77 | + setVisible(false); | ||
78 | + } | ||
79 | + } | ||
80 | + }); | ||
81 | + | ||
82 | + pack(); | ||
83 | + setLocationRelativeTo(null); | ||
84 | + | ||
85 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
86 | + } | ||
87 | + | ||
88 | + @Action | ||
89 | + public void monitor() { | ||
90 | + setVisible(true); | ||
91 | + } | ||
92 | + | ||
93 | + private class UpdateTask extends TimerTask { | ||
94 | + @Override | ||
95 | + public void run() { | ||
96 | + if (isVisible()) { | ||
97 | + for (int i = 1; i <= WWPreferences.WIIMOTES; i++) | ||
98 | + for (int j = 0; j < 4; j++) { | ||
99 | + if (labels[i][j] != null) | ||
100 | + labels[i][j].update(); | ||
101 | + } | ||
102 | + } | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
107 | + this.lights[wiimote.getId()] = lights; | ||
108 | + } | ||
109 | + | ||
110 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
111 | + } | ||
112 | + | ||
113 | + public void batteryLevel(Wiimote wiimote, double level) { | ||
114 | + } | ||
115 | + | ||
116 | + public void wiimoteConnected(Wiimote wiimote) { | ||
117 | + for (int i = 0; i < 4; i++) | ||
118 | + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1)); | ||
119 | + } | ||
120 | + | ||
121 | + public void wiimoteDisconnected(Wiimote wiimote) { | ||
122 | + for (int i = 0; i < 4; i++) { | ||
123 | + canvas.remove(labels[wiimote.getId()][i]); | ||
124 | + labels[wiimote.getId()][i] = null; | ||
125 | + } | ||
126 | + } | ||
127 | + | ||
128 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpBook.java
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpBook.java~
0 → 100644
@@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +public class HelpBook { | ||
29 | + static { | ||
30 | + System.loadLibrary("HelpBookJNI"); | ||
31 | + } | ||
32 | + | ||
33 | + public static native void launchHelpViewer(); | ||
34 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpHandler.java
0 → 100644
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import javax.swing.JOptionPane; | ||
4 | + | ||
5 | +import org.jdesktop.application.Action; | ||
6 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
7 | +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch; | ||
8 | +import org.mote.wiimote.whiteboard.util.Util; | ||
9 | + | ||
10 | +@SuppressWarnings("serial") | ||
11 | +public class HelpHandler { | ||
12 | + | ||
13 | + @Action | ||
14 | + public void help() { | ||
15 | + if (Util.INSIDE_APP_BUNDLE) { | ||
16 | + HelpBook.launchHelpViewer(); | ||
17 | + } else { | ||
18 | + if (JOptionPane.showConfirmDialog(null, Util.getResourceMap(HelpHandler.class).getString("helpQuestion"), Util.getResourceMap(HelpHandler.class).getString("help.Action.text"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { | ||
19 | + BareBonesBrowserLaunch.openURL(WiimoteWhiteboard.getProperty("onlineHelp")); | ||
20 | + } | ||
21 | + } | ||
22 | + } | ||
23 | + | ||
24 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpHandler.java~
0 → 100644
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import javax.swing.JOptionPane; | ||
29 | + | ||
30 | +import org.jdesktop.application.Action; | ||
31 | +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard; | ||
32 | +import org.uweschmidt.wiimote.whiteboard.util.BareBonesBrowserLaunch; | ||
33 | +import org.uweschmidt.wiimote.whiteboard.util.Util; | ||
34 | + | ||
35 | +@SuppressWarnings("serial") | ||
36 | +public class HelpHandler { | ||
37 | + | ||
38 | + @Action | ||
39 | + public void help() { | ||
40 | + if (Util.INSIDE_APP_BUNDLE) { | ||
41 | + HelpBook.launchHelpViewer(); | ||
42 | + } else { | ||
43 | + if (JOptionPane.showConfirmDialog(null, Util.getResourceMap(HelpHandler.class).getString("helpQuestion"), Util.getResourceMap(HelpHandler.class).getString("help.Action.text"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { | ||
44 | + BareBonesBrowserLaunch.openURL(WiimoteWhiteboard.getProperty("onlineHelp")); | ||
45 | + } | ||
46 | + } | ||
47 | + } | ||
48 | + | ||
49 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LightLabel.java
0 → 100644
@@ -0,0 +1,70 @@ | @@ -0,0 +1,70 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Color; | ||
4 | +import java.awt.Graphics; | ||
5 | +import java.awt.Graphics2D; | ||
6 | +import java.awt.RenderingHints; | ||
7 | +import java.awt.geom.Point2D; | ||
8 | + | ||
9 | +import javax.swing.JLabel; | ||
10 | +import javax.swing.JPanel; | ||
11 | +import javax.swing.SwingConstants; | ||
12 | + | ||
13 | +import org.uweschmidt.wiimote.whiteboard.ds.IRDot; | ||
14 | + | ||
15 | +@SuppressWarnings("serial") | ||
16 | +public class LightLabel extends JLabel { | ||
17 | + | ||
18 | + private static final int RADIUS = 10; | ||
19 | + | ||
20 | + private final int id, number; | ||
21 | + private Point2D[][] lights; | ||
22 | + private JPanel canvas; | ||
23 | + | ||
24 | + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number) { | ||
25 | + this(canvas, lights, id, number, WiimoteIcon.COLORS[id - 1]); | ||
26 | + } | ||
27 | + | ||
28 | + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number, Color bg) { | ||
29 | + super(String.valueOf(number)); | ||
30 | + this.id = id; | ||
31 | + this.number = number; | ||
32 | + this.lights = lights; | ||
33 | + this.canvas = canvas; | ||
34 | + setHorizontalAlignment(SwingConstants.CENTER); | ||
35 | + setForeground(Color.black); | ||
36 | + setBackground(bg); | ||
37 | + } | ||
38 | + | ||
39 | + public void update() { | ||
40 | + Point2D l = lights[id][number - 1]; | ||
41 | + if (l != null) { | ||
42 | + int x = (int) Math.round(l.getX() * canvas.getWidth()); | ||
43 | + int y = canvas.getHeight() - (int) Math.round(l.getY() * canvas.getHeight()); | ||
44 | + this.setBounds(x - RADIUS, y - RADIUS, RADIUS * 2, RADIUS * 2); | ||
45 | + setVisible(true); | ||
46 | + } else { | ||
47 | + setVisible(false); | ||
48 | + } | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + protected void paintComponent(Graphics g) { | ||
53 | + Graphics2D g2d = (Graphics2D) g; | ||
54 | + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
55 | + if (lights[id][number - 1] != null) { | ||
56 | + g2d.setColor(this.getBackground()); | ||
57 | + g2d.fillOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2); | ||
58 | + g2d.setColor(this.getForeground()); | ||
59 | + g2d.drawOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2); | ||
60 | + | ||
61 | + double scale = lights[id][number - 1] instanceof IRDot ? ((IRDot)lights[id][number - 1]).getSize() : -1; | ||
62 | + if (scale != -1) { | ||
63 | + g2d.setColor(Color.cyan); | ||
64 | + final int d = (int)Math.round(RADIUS * scale * 10); | ||
65 | + g2d.fillOval(RADIUS - d/2, RADIUS - d/2, d, d); | ||
66 | + } | ||
67 | + } | ||
68 | + super.paintComponent(g); | ||
69 | + } | ||
70 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LightLabel.java~
0 → 100644
@@ -0,0 +1,98 @@ | @@ -0,0 +1,98 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import java.awt.Color; | ||
29 | +import java.awt.Graphics; | ||
30 | +import java.awt.Graphics2D; | ||
31 | +import java.awt.RenderingHints; | ||
32 | +import java.awt.geom.Point2D; | ||
33 | + | ||
34 | +import javax.swing.JLabel; | ||
35 | +import javax.swing.JPanel; | ||
36 | +import javax.swing.SwingConstants; | ||
37 | + | ||
38 | +import org.uweschmidt.wiimote.whiteboard.ds.IRDot; | ||
39 | + | ||
40 | +@SuppressWarnings("serial") | ||
41 | +public class LightLabel extends JLabel { | ||
42 | + | ||
43 | + private static final int RADIUS = 10; | ||
44 | + | ||
45 | + private final int id, number; | ||
46 | + private Point2D[][] lights; | ||
47 | + private JPanel canvas; | ||
48 | + | ||
49 | + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number) { | ||
50 | + this(canvas, lights, id, number, WiimoteIcon.COLORS[id - 1]); | ||
51 | + } | ||
52 | + | ||
53 | + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number, Color bg) { | ||
54 | + super(String.valueOf(number)); | ||
55 | + this.id = id; | ||
56 | + this.number = number; | ||
57 | + this.lights = lights; | ||
58 | + this.canvas = canvas; | ||
59 | + // setOpaque(true); | ||
60 | + setHorizontalAlignment(SwingConstants.CENTER); | ||
61 | + // setBorder(BorderFactory.createLineBorder(Color.black)); | ||
62 | + setForeground(Color.black); | ||
63 | + setBackground(bg); | ||
64 | + } | ||
65 | + | ||
66 | + public void update() { | ||
67 | + Point2D l = lights[id][number - 1]; | ||
68 | + if (l != null) { | ||
69 | + int x = (int) Math.round(l.getX() * canvas.getWidth()); | ||
70 | + int y = canvas.getHeight() - (int) Math.round(l.getY() * canvas.getHeight()); | ||
71 | + this.setBounds(x - RADIUS, y - RADIUS, RADIUS * 2, RADIUS * 2); | ||
72 | + setVisible(true); | ||
73 | + } else { | ||
74 | + setVisible(false); | ||
75 | + } | ||
76 | + } | ||
77 | + | ||
78 | + @Override | ||
79 | + protected void paintComponent(Graphics g) { | ||
80 | + Graphics2D g2d = (Graphics2D) g; | ||
81 | + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
82 | + if (lights[id][number - 1] != null) { | ||
83 | + g2d.setColor(this.getBackground()); | ||
84 | + g2d.fillOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2); | ||
85 | + g2d.setColor(this.getForeground()); | ||
86 | + g2d.drawOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2); | ||
87 | + | ||
88 | + // XXX explain cyan oval for size | ||
89 | + double scale = lights[id][number - 1] instanceof IRDot ? ((IRDot)lights[id][number - 1]).getSize() : -1; | ||
90 | + if (scale != -1) { | ||
91 | + g2d.setColor(Color.cyan); | ||
92 | + final int d = (int)Math.round(RADIUS * scale * 10); | ||
93 | + g2d.fillOval(RADIUS - d/2, RADIUS - d/2, d, d); | ||
94 | + } | ||
95 | + } | ||
96 | + super.paintComponent(g); | ||
97 | + } | ||
98 | +} | ||
0 | \ No newline at end of file | 99 | \ No newline at end of file |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LogWindow.java
0 → 100644
@@ -0,0 +1,134 @@ | @@ -0,0 +1,134 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.BorderLayout; | ||
4 | +import java.awt.event.KeyAdapter; | ||
5 | +import java.awt.event.KeyEvent; | ||
6 | +import java.io.PrintWriter; | ||
7 | +import java.io.StringWriter; | ||
8 | +import java.io.Writer; | ||
9 | +import java.util.Calendar; | ||
10 | +import java.util.logging.Handler; | ||
11 | +import java.util.logging.Level; | ||
12 | +import java.util.logging.LogRecord; | ||
13 | +import java.util.logging.Logger; | ||
14 | + | ||
15 | +import javax.swing.JDialog; | ||
16 | +import javax.swing.JLabel; | ||
17 | +import javax.swing.JScrollPane; | ||
18 | +import javax.swing.JTextArea; | ||
19 | + | ||
20 | +import net.miginfocom.swing.MigLayout; | ||
21 | + | ||
22 | +import org.jdesktop.application.Action; | ||
23 | +import org.jdesktop.application.Application; | ||
24 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
25 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
26 | +import org.mote.wiimote.whiteboard.util.Util; | ||
27 | + | ||
28 | +@SuppressWarnings("serial") | ||
29 | +public class LogWindow extends JDialog { | ||
30 | + | ||
31 | + private JTextArea log; | ||
32 | + private JDialog failedDialog; | ||
33 | + | ||
34 | + public LogWindow() { | ||
35 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), WiimoteWhiteboard.getProperty("id") + " " + Util.getResourceMap(LogWindow.class).getString("log.Action.text")); | ||
36 | + getRootPane().putClientProperty("Window.style", "small"); | ||
37 | + setLayout(new MigLayout()); | ||
38 | + | ||
39 | + log = Util.newComponent(JTextArea.class, "log"); | ||
40 | + add(new JScrollPane(log), "w 66sp, h 33sp, grow, push"); | ||
41 | + | ||
42 | + Logger.getLogger("wiiremotej").addHandler(new LogHandler("WiiRemoteJ: ")); | ||
43 | + WiimoteWhiteboard.getLogger().addHandler(new LogHandler("")); | ||
44 | + | ||
45 | + log.addKeyListener(new KeyAdapter() { | ||
46 | + @Override | ||
47 | + public void keyPressed(KeyEvent e) { | ||
48 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
49 | + setVisible(false); | ||
50 | + } | ||
51 | + } | ||
52 | + }); | ||
53 | + | ||
54 | + Util.getResourceMap(LogWindow.class).injectComponents(this); | ||
55 | + pack(); | ||
56 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
57 | + | ||
58 | + failedDialog = Util.newComponent(JDialog.class, "failedDialog"); | ||
59 | + failedDialog.addKeyListener(new KeyAdapter() { | ||
60 | + @Override | ||
61 | + public void keyPressed(KeyEvent e) { | ||
62 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
63 | + failedDialog.setVisible(false); | ||
64 | + } | ||
65 | + } | ||
66 | + }); | ||
67 | + failedDialog.setAlwaysOnTop(true); | ||
68 | + failedDialog.getRootPane().putClientProperty("Window.style", "small"); | ||
69 | + failedDialog.getRootPane().putClientProperty("Window.alpha", new Float(0.90)); | ||
70 | + failedDialog.setLayout(new BorderLayout()); | ||
71 | + failedDialog.add(Util.newComponent(JLabel.class, "failedLabel"), BorderLayout.CENTER); | ||
72 | + Util.getResourceMap(LogWindow.class).injectComponents(failedDialog); | ||
73 | + failedDialog.pack(); | ||
74 | + failedDialog.setBounds(getX()+getWidth()/2-(failedDialog.getWidth()+20)/2, getY()+getHeight()+10, failedDialog.getWidth()+20, failedDialog.getHeight()+20); | ||
75 | + } | ||
76 | + | ||
77 | + @Action | ||
78 | + public void log() { | ||
79 | + setVisible(!isVisible()); | ||
80 | + } | ||
81 | + | ||
82 | + private class LogHandler extends Handler { | ||
83 | + private static final String DIRECT_CONNECTION_TIMEOUT = "Failed to open baseband connection"; | ||
84 | + private static final String CONNECTION_FAILED = "WiiRemote failed to connect!"; | ||
85 | + private static final String CONNECTION_SUCCEEDED = "Initial connection complete."; | ||
86 | + private final String name; | ||
87 | + public LogHandler(String name) { | ||
88 | + this.name = name; | ||
89 | + setLevel(Level.ALL); | ||
90 | + } | ||
91 | + @Override | ||
92 | + public void close() throws SecurityException {} | ||
93 | + @Override | ||
94 | + public void flush() {} | ||
95 | + | ||
96 | + @Override | ||
97 | + public void publish(LogRecord record) { | ||
98 | + Level level = record.getLevel(); | ||
99 | + String msg = record.getMessage(); | ||
100 | + Throwable e = record.getThrown(); | ||
101 | + boolean failed = false; | ||
102 | + | ||
103 | + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty() && e != null && e.getCause() != null && e.getCause().getMessage().startsWith(DIRECT_CONNECTION_TIMEOUT)) | ||
104 | + return; | ||
105 | + | ||
106 | + log.append(String.format("%7s %tT %s%s\n", level.getName(), Calendar.getInstance(), name, msg)); | ||
107 | + if (e != null) { | ||
108 | + log.append(getStackTrace(e)); | ||
109 | + failed = CONNECTION_FAILED.equals(e.getMessage()); | ||
110 | + } | ||
111 | + log.setCaretPosition(log.getText().length()-1); | ||
112 | + | ||
113 | + if (!failed && level == Level.SEVERE) { | ||
114 | + if (!LogWindow.this.isVisible()) { | ||
115 | + LogWindow.this.setVisible(true); | ||
116 | + } | ||
117 | + } | ||
118 | + | ||
119 | + if (CONNECTION_SUCCEEDED.equals(msg)) { | ||
120 | + failedDialog.setVisible(false); | ||
121 | + } else if (failed) { | ||
122 | + failedDialog.setVisible(true); | ||
123 | + } | ||
124 | + } | ||
125 | + } | ||
126 | + | ||
127 | + private static String getStackTrace(Throwable e) { | ||
128 | + final Writer result = new StringWriter(); | ||
129 | + final PrintWriter printWriter = new PrintWriter(result); | ||
130 | + e.printStackTrace(printWriter); | ||
131 | + return result.toString(); | ||
132 | + } | ||
133 | + | ||
134 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LogWindow.java~
0 → 100644
@@ -0,0 +1,171 @@ | @@ -0,0 +1,171 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import java.awt.BorderLayout; | ||
29 | +import java.awt.event.KeyAdapter; | ||
30 | +import java.awt.event.KeyEvent; | ||
31 | +import java.io.PrintWriter; | ||
32 | +import java.io.StringWriter; | ||
33 | +import java.io.Writer; | ||
34 | +import java.util.Calendar; | ||
35 | +import java.util.logging.Handler; | ||
36 | +import java.util.logging.Level; | ||
37 | +import java.util.logging.LogRecord; | ||
38 | +import java.util.logging.Logger; | ||
39 | + | ||
40 | +import javax.swing.JDialog; | ||
41 | +import javax.swing.JLabel; | ||
42 | +import javax.swing.JScrollPane; | ||
43 | +import javax.swing.JTextArea; | ||
44 | + | ||
45 | +import net.miginfocom.swing.MigLayout; | ||
46 | + | ||
47 | +import org.jdesktop.application.Action; | ||
48 | +import org.jdesktop.application.Application; | ||
49 | +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard; | ||
50 | +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences; | ||
51 | +import org.uweschmidt.wiimote.whiteboard.util.Util; | ||
52 | + | ||
53 | +@SuppressWarnings("serial") | ||
54 | +public class LogWindow extends JDialog { | ||
55 | + | ||
56 | + private JTextArea log; | ||
57 | + private JDialog failedDialog; | ||
58 | + | ||
59 | + public LogWindow() { | ||
60 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), WiimoteWhiteboard.getProperty("id") + " " + Util.getResourceMap(LogWindow.class).getString("log.Action.text")); | ||
61 | + getRootPane().putClientProperty("Window.style", "small"); | ||
62 | +// setLayout(new BorderLayout()); | ||
63 | + setLayout(new MigLayout()); | ||
64 | +// if (getContentPane() instanceof JPanel) { | ||
65 | +// ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||
66 | +// } | ||
67 | + | ||
68 | + log = Util.newComponent(JTextArea.class, "log"); | ||
69 | +// add(new JScrollPane(log), BorderLayout.CENTER); | ||
70 | + add(new JScrollPane(log), "w 66sp, h 33sp, grow, push"); | ||
71 | + | ||
72 | + Logger.getLogger("wiiremotej").addHandler(new LogHandler("WiiRemoteJ: ")); | ||
73 | + WiimoteWhiteboard.getLogger().addHandler(new LogHandler("")); | ||
74 | + | ||
75 | + log.addKeyListener(new KeyAdapter() { | ||
76 | + @Override | ||
77 | + public void keyPressed(KeyEvent e) { | ||
78 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
79 | + setVisible(false); | ||
80 | + } | ||
81 | + } | ||
82 | + }); | ||
83 | + | ||
84 | + Util.getResourceMap(LogWindow.class).injectComponents(this); | ||
85 | + pack(); | ||
86 | +// Util.placeDialogWindow(this, 500, 300); | ||
87 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
88 | + | ||
89 | + failedDialog = Util.newComponent(JDialog.class, "failedDialog"); | ||
90 | + failedDialog.addKeyListener(new KeyAdapter() { | ||
91 | + @Override | ||
92 | + public void keyPressed(KeyEvent e) { | ||
93 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
94 | + failedDialog.setVisible(false); | ||
95 | + } | ||
96 | + } | ||
97 | + }); | ||
98 | + failedDialog.setAlwaysOnTop(true); | ||
99 | + failedDialog.getRootPane().putClientProperty("Window.style", "small"); | ||
100 | + failedDialog.getRootPane().putClientProperty("Window.alpha", new Float(0.90)); | ||
101 | + failedDialog.setLayout(new BorderLayout()); | ||
102 | + failedDialog.add(Util.newComponent(JLabel.class, "failedLabel"), BorderLayout.CENTER); | ||
103 | + Util.getResourceMap(LogWindow.class).injectComponents(failedDialog); | ||
104 | + failedDialog.pack(); | ||
105 | +// failedDialog.setBounds(getX(), getY()+getHeight()+10, getWidth(), failedDialog.getHeight()+20); | ||
106 | + failedDialog.setBounds(getX()+getWidth()/2-(failedDialog.getWidth()+20)/2, getY()+getHeight()+10, failedDialog.getWidth()+20, failedDialog.getHeight()+20); | ||
107 | +// failedDialog.setVisible(true); | ||
108 | + } | ||
109 | + | ||
110 | + @Action | ||
111 | + public void log() { | ||
112 | + setVisible(!isVisible()); | ||
113 | + } | ||
114 | + | ||
115 | + private class LogHandler extends Handler { | ||
116 | + private static final String DIRECT_CONNECTION_TIMEOUT = "Failed to open baseband connection"; | ||
117 | + private static final String CONNECTION_FAILED = "WiiRemote failed to connect!"; | ||
118 | + private static final String CONNECTION_SUCCEEDED = "Initial connection complete."; | ||
119 | + private final String name; | ||
120 | + public LogHandler(String name) { | ||
121 | + this.name = name; | ||
122 | + setLevel(Level.ALL); | ||
123 | + } | ||
124 | + @Override | ||
125 | + public void close() throws SecurityException {} | ||
126 | + @Override | ||
127 | + public void flush() {} | ||
128 | + | ||
129 | + @Override | ||
130 | + public void publish(LogRecord record) { | ||
131 | + Level level = record.getLevel(); | ||
132 | + String msg = record.getMessage(); | ||
133 | + Throwable e = record.getThrown(); | ||
134 | + boolean failed = false; | ||
135 | + | ||
136 | + // skip that error (apparently timeout on direct connection attempts) | ||
137 | + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty() && e != null && e.getCause() != null && e.getCause().getMessage().startsWith(DIRECT_CONNECTION_TIMEOUT)) | ||
138 | + return; | ||
139 | + | ||
140 | + log.append(String.format("%7s %tT %s%s\n", level.getName(), Calendar.getInstance(), name, msg)); | ||
141 | + if (e != null) { | ||
142 | + log.append(getStackTrace(e)); | ||
143 | + failed = CONNECTION_FAILED.equals(e.getMessage()); | ||
144 | + } | ||
145 | + log.setCaretPosition(log.getText().length()-1); | ||
146 | + | ||
147 | + if (!failed && level == Level.SEVERE) { | ||
148 | + if (!LogWindow.this.isVisible()) { | ||
149 | +// LogWindow.this.pack(); | ||
150 | +// Util.placeDialogWindow(LogWindow.this, LogWindow.this.getWidth(), LogWindow.this.getHeight()); | ||
151 | + LogWindow.this.setVisible(true); | ||
152 | + } | ||
153 | + } | ||
154 | + | ||
155 | + if (CONNECTION_SUCCEEDED.equals(msg)) { | ||
156 | +// LogWindow.this.setVisible(false); | ||
157 | + failedDialog.setVisible(false); | ||
158 | + } else if (failed) { | ||
159 | + failedDialog.setVisible(true); | ||
160 | + } | ||
161 | + } | ||
162 | + } | ||
163 | + | ||
164 | + private static String getStackTrace(Throwable e) { | ||
165 | + final Writer result = new StringWriter(); | ||
166 | + final PrintWriter printWriter = new PrintWriter(result); | ||
167 | + e.printStackTrace(printWriter); | ||
168 | + return result.toString(); | ||
169 | + } | ||
170 | + | ||
171 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MainPanel.java
0 → 100644
@@ -0,0 +1,332 @@ | @@ -0,0 +1,332 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Color; | ||
4 | +import java.awt.Font; | ||
5 | +import java.awt.Graphics; | ||
6 | +import java.awt.Point; | ||
7 | +import java.awt.SystemColor; | ||
8 | +import java.awt.event.ActionEvent; | ||
9 | +import java.awt.event.ActionListener; | ||
10 | +import java.awt.event.WindowEvent; | ||
11 | +import java.awt.event.WindowFocusListener; | ||
12 | +import java.util.Map; | ||
13 | +import java.util.logging.Level; | ||
14 | + | ||
15 | +import javax.swing.BorderFactory; | ||
16 | +import javax.swing.ButtonGroup; | ||
17 | +import javax.swing.ImageIcon; | ||
18 | +import javax.swing.JButton; | ||
19 | +import javax.swing.JCheckBox; | ||
20 | +import javax.swing.JLabel; | ||
21 | +import javax.swing.JOptionPane; | ||
22 | +import javax.swing.JPanel; | ||
23 | +import javax.swing.JProgressBar; | ||
24 | +import javax.swing.JRadioButton; | ||
25 | +import javax.swing.JSeparator; | ||
26 | +import javax.swing.SwingConstants; | ||
27 | + | ||
28 | +import net.miginfocom.swing.MigLayout; | ||
29 | + | ||
30 | +import org.jdesktop.application.Action; | ||
31 | +import org.jdesktop.application.Application; | ||
32 | +import org.jdesktop.application.ResourceMap; | ||
33 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler; | ||
34 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
35 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
36 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
37 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
38 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener; | ||
39 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
40 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
41 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
42 | +import org.mote.wiimote.whiteboard.util.Util; | ||
43 | + | ||
44 | +@SuppressWarnings("serial") | ||
45 | +public class MainPanel extends JPanel implements WiimoteDataListener, CalibrationEventListener { | ||
46 | + | ||
47 | + private static final ImageIcon CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/ok.png")); | ||
48 | + private static final ImageIcon NOT_CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/warning.png")); | ||
49 | + | ||
50 | + private static final WWPreferences prefs = WWPreferences.getPreferences(); | ||
51 | + | ||
52 | + private DotLabel[] dotLabel = new DotLabel[4]; | ||
53 | + private JProgressBar[] batteryLevel = new JProgressBar[WWPreferences.WIIMOTES]; | ||
54 | + private JButton[] resetButton = new JButton[WWPreferences.WIIMOTES]; | ||
55 | + private WiimoteIcon[] wiimoteIcon = new WiimoteIcon[WWPreferences.WIIMOTES]; | ||
56 | + private JLabel[] statusLabel = new JLabel[WWPreferences.WIIMOTES]; | ||
57 | + private JCheckBox cursorControl; | ||
58 | + private JRadioButton moveMouse, leftClick; | ||
59 | + private JButton calibrationButton, cameraButton | ||
60 | + private ScreenSelector screenSelector; | ||
61 | + | ||
62 | + private boolean notifiedLowBattery = false; | ||
63 | + | ||
64 | + private Wiimote[] wiimotes = new Wiimote[WWPreferences.WIIMOTES]; | ||
65 | + | ||
66 | + private WiimoteDataHandler dh; | ||
67 | + private WiimoteCalibration calibration; | ||
68 | + private ResourceMap r = Util.getResourceMap(MainPanel.class); | ||
69 | + | ||
70 | + public MainPanel(WiimoteDataHandler dh, WiimoteCalibration calibration) { | ||
71 | + this.dh = dh; | ||
72 | + this.calibration = calibration; | ||
73 | + | ||
74 | + dh.addWiimoteDataListener(this); | ||
75 | + calibration.addCalibrationEventListener(this); | ||
76 | + | ||
77 | + createComponents(); | ||
78 | + | ||
79 | + getValues(); | ||
80 | + update(); | ||
81 | + } | ||
82 | + | ||
83 | + public void getValues() { | ||
84 | + cursorControl.setSelected(dh.isCursorControl()); | ||
85 | + leftClick.setSelected(prefs.isLeftClick()); | ||
86 | + moveMouse.setSelected(!prefs.isLeftClick()); | ||
87 | + } | ||
88 | + | ||
89 | + public void calibrationEvent(CalibrationEvent e) { | ||
90 | + switch (e) { | ||
91 | + case FINISHED: | ||
92 | + case LOADED: | ||
93 | + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION); | ||
94 | + case STARTED: | ||
95 | + case SCREEN_CHANGED: | ||
96 | + case ABORTED: | ||
97 | + update(); | ||
98 | + break; | ||
99 | + } | ||
100 | + } | ||
101 | + | ||
102 | + public void batteryLevel(Wiimote wiimote, double level) { | ||
103 | + batteryLevel[wiimote.getId()-1].setValue((int) Math.round(level * 100)); | ||
104 | + batteryLevel[wiimote.getId()-1].setString(r.getString("batteryLevel", level * 100)); | ||
105 | + | ||
106 | + if (!notifiedLowBattery && prefs.isLowBatteryWarning() && dh.isConnected(wiimote) && level <= .05) { | ||
107 | + notifiedLowBattery = true; | ||
108 | + WiimoteWhiteboard.getLogger().log(Level.WARNING, r.getString("lowBattery")); | ||
109 | + new Thread(new Runnable() { | ||
110 | + public void run() { | ||
111 | + JOptionPane.showMessageDialog(null, r.getString("lowBattery"), WiimoteWhiteboard.getProperty("id"), JOptionPane.WARNING_MESSAGE); | ||
112 | + } | ||
113 | + }).start(); | ||
114 | + } | ||
115 | + } | ||
116 | + | ||
117 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
118 | + for (int i = 0; i < lights.length; i++) { | ||
119 | + dotLabel[i].update(wiimote, lights[i] != null); | ||
120 | + } | ||
121 | + } | ||
122 | + | ||
123 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
124 | + } | ||
125 | + | ||
126 | + public void wiimoteConnected(Wiimote wiimote) { | ||
127 | + wiimotes[wiimote.getId()-1] = wiimote; | ||
128 | + | ||
129 | + if (wiimote.getId() > 1) { | ||
130 | + for (int i = 0; i < wiimote.getId(); i++) { | ||
131 | + wiimoteIcon[i].setVisible(true); | ||
132 | + } | ||
133 | + } | ||
134 | + statusLabel[wiimote.getId()-1].setVisible(true); | ||
135 | + | ||
136 | + batteryLevel[wiimote.getId()-1].setVisible(true); | ||
137 | + resetButton[wiimote.getId()-1].setVisible(true); | ||
138 | + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION); | ||
139 | + update(); | ||
140 | + } | ||
141 | + | ||
142 | + public void wiimoteDisconnected(Wiimote wiimote) { | ||
143 | + if (wiimote.getId() != 1) batteryLevel[wiimote.getId()-1].setVisible(false); | ||
144 | + if (wiimote.getId() != 1) wiimoteIcon[wiimote.getId()-1].setVisible(false); | ||
145 | + if (wiimote.getId() != 1) resetButton[wiimote.getId()-1].setVisible(false); | ||
146 | + if (wiimote.getId() != 1) statusLabel[wiimote.getId()-1].setVisible(false); | ||
147 | + update(); | ||
148 | + JOptionPane.showMessageDialog(null, r.getString("disconnected", wiimote.getId()), WiimoteWhiteboard.getProperty("id"), JOptionPane.ERROR_MESSAGE); | ||
149 | + Application.getInstance(WiimoteWhiteboard.class).exit(); | ||
150 | + } | ||
151 | + | ||
152 | + | ||
153 | + /* | ||
154 | + * UPDATE UI WIDGETS | ||
155 | + */ | ||
156 | + | ||
157 | + @Action | ||
158 | + public void update() { | ||
159 | + calibrationButton.setEnabled(dh.isConnected()); | ||
160 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
161 | + resetButton[i].setEnabled(dh.isConnected(wiimotes[i])); | ||
162 | + wiimoteIcon[i].displayConnected(dh.isConnected(wiimotes[i])); | ||
163 | + if (dh.isConnected(wiimotes[i])) { | ||
164 | + boolean calibrated = calibration.isCalibrated(wiimotes[i]); | ||
165 | + statusLabel[i].setText(r.getString(calibrated ? "calibrated" : "notCalibrated")); | ||
166 | + statusLabel[i].setIcon(calibrated ? CALIBRATED : NOT_CALIBRATED); | ||
167 | + } | ||
168 | + } | ||
169 | + cameraButton.setEnabled(dh.isConnected()); | ||
170 | + screenSelector.setEnabled(dh.isConnected() && !calibration.inProgress()); | ||
171 | + | ||
172 | + if (!dh.isConnected()) { | ||
173 | + batteryLevel[0].setString(r.getString("searching")); | ||
174 | + batteryLevel[0].setValue(0); | ||
175 | + batteryLevel[0].setToolTipText(Util.getResourceMap(MainPanel.class).getString("batteryLevelBar.toolTipText")); | ||
176 | + } else { | ||
177 | + batteryLevel[0].setToolTipText(null); | ||
178 | + } | ||
179 | + | ||
180 | + cursorControl.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes())); | ||
181 | + if (!cursorControl.isEnabled()) | ||
182 | + cursorControl.setSelected(false); | ||
183 | + | ||
184 | + moveMouse.setEnabled(cursorControl.isSelected()); | ||
185 | + leftClick.setEnabled(cursorControl.isSelected()); | ||
186 | + | ||
187 | + dh.setCursorControl(cursorControl.isSelected()); | ||
188 | + prefs.setLeftClick(leftClick.isSelected()); | ||
189 | + } | ||
190 | + | ||
191 | + /* | ||
192 | + * MAIN PANEL | ||
193 | + */ | ||
194 | + | ||
195 | + private void createComponents() { | ||
196 | + setLayout(new MigLayout("nocache, hidemode 3, gap 0", "[fill]")); | ||
197 | + | ||
198 | + addHeadline(r.getString("wiimoteHeadline"), false); | ||
199 | + | ||
200 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
201 | + add(wiimoteIcon[i] = new WiimoteIcon(i+1), "split"); | ||
202 | + if (i > 0) wiimoteIcon[i].setVisible(false); | ||
203 | + } | ||
204 | + | ||
205 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
206 | + add(batteryLevel[i] = Util.newComponent(JProgressBar.class, "batteryLevelBar"), (i == 0 ? "newline related/2, " : "") + "split"); | ||
207 | + if (i > 0) batteryLevel[i].setVisible(false); | ||
208 | + } | ||
209 | + | ||
210 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
211 | + add(statusLabel[i] = Util.newComponent(JLabel.class, "statusLabel"), (i == 0 ? "newline related/2, split, " : "") + "sg, h 16!, center"); | ||
212 | + statusLabel[i].setFont(statusLabel[i].getFont().deriveFont(10f)); | ||
213 | + if (i > 0) statusLabel[i].setVisible(false); | ||
214 | + } | ||
215 | + | ||
216 | + String gap = Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "0" : "related/2"; | ||
217 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
218 | + final int j = i; | ||
219 | + add(resetButton[i] = Util.newComponent(JButton.class, "resetCameraButton"), (i == 0 ? "newline "+gap+", split, " : "") + ""); | ||
220 | + resetButton[i].putClientProperty("JButton.buttonType", "textured"); | ||
221 | + resetButton[i].putClientProperty("JComponent.sizeVariant", "small"); | ||
222 | + resetButton[i].addActionListener(new ActionListener() { | ||
223 | + public void actionPerformed(ActionEvent e) { | ||
224 | + try { | ||
225 | + dh.enableIR(wiimotes[j]); | ||
226 | + } catch (Exception e1) { | ||
227 | + e1.printStackTrace(); | ||
228 | + } | ||
229 | + } | ||
230 | + }); | ||
231 | + if (i > 0) resetButton[i].setVisible(false); | ||
232 | + } | ||
233 | + | ||
234 | + add(new JSeparator(), String.format("newline %s, span, growx, wrap related", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "related/3" : "related")); | ||
235 | + | ||
236 | + add(Util.newComponent(JLabel.class, "visibleDotsLabel"), "split" + (Util.MAC_OS_X ? ", gapleft 4" : "")); | ||
237 | + add(dotLabel[0] = new DotLabel("1"), "w 18, h 18"); | ||
238 | + add(dotLabel[1] = new DotLabel("2"), "w 18, h 18"); | ||
239 | + add(dotLabel[2] = new DotLabel("3"), "w 18, h 18"); | ||
240 | + add(dotLabel[3] = new DotLabel("4"), "w 18, h 18, wrap related" + (Util.MAC_OS_X ? ", gapright 4" : "")); | ||
241 | + | ||
242 | + add(cameraButton = new JButton(Util.getAction(new CameraMonitor(dh), "monitor")), ""); | ||
243 | + cameraButton.putClientProperty("JButton.buttonType", "textured"); | ||
244 | + | ||
245 | + // CALIBRATION | ||
246 | + | ||
247 | + addHeadline(r.getString("calibrationHeadline")); | ||
248 | + | ||
249 | + | ||
250 | + final JButton infoButton = new JButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info")); | ||
251 | + infoButton.putClientProperty("JButton.buttonType", "textured"); | ||
252 | + infoButton.putClientProperty("JComponent.sizeVariant", "small"); | ||
253 | + add(infoButton, "wrap related"); | ||
254 | + | ||
255 | + | ||
256 | + add(screenSelector = new ScreenSelector(calibration, dh), "align center, grow 0, wrap related"); | ||
257 | + | ||
258 | + add(calibrationButton = Util.newComponent(JButton.class, "calibrationButton"), ""); | ||
259 | + calibrationButton.putClientProperty("JButton.buttonType", "textured"); | ||
260 | + calibrationButton.addActionListener(new ActionListener() { | ||
261 | + public void actionPerformed(ActionEvent e) { | ||
262 | + calibration.start(dh.getConnectedWiimotes()); | ||
263 | + } | ||
264 | + }); | ||
265 | + | ||
266 | + // MOUSE CONTROL | ||
267 | + | ||
268 | + addHeadline(r.getString("mouseControlHeadline")); | ||
269 | + | ||
270 | + add(cursorControl = Util.newComponent(JCheckBox.class, "cursorControl"), "wrap related"); | ||
271 | + add(moveMouse = Util.newComponent(JRadioButton.class, "moveMouse"), "pad 0 20 0 0, wmin pref+20, wrap related"); | ||
272 | + add(leftClick = Util.newComponent(JRadioButton.class, "leftClick"), "pad 0 20 0 0, wmin pref+20, wrap"); | ||
273 | + | ||
274 | + ButtonGroup group = new ButtonGroup(); | ||
275 | + group.add(moveMouse); | ||
276 | + group.add(leftClick); | ||
277 | + | ||
278 | + cursorControl.addActionListener(Util.getAction(this, "update")); | ||
279 | + moveMouse.addActionListener(Util.getAction(this, "update")); | ||
280 | + leftClick.addActionListener(Util.getAction(this, "update")); | ||
281 | + | ||
282 | + Application.getInstance(WiimoteWhiteboard.class).getMainFrame().addWindowFocusListener(new WindowFocusListener() { | ||
283 | + public void windowGainedFocus(WindowEvent e) { | ||
284 | + updateUI(); | ||
285 | + } | ||
286 | + public void windowLostFocus(WindowEvent e) {} | ||
287 | + }); | ||
288 | + | ||
289 | + Util.getResourceMap(MainPanel.class).injectComponents(this); | ||
290 | + } | ||
291 | + | ||
292 | + private JLabel addHeadline(String name) { | ||
293 | + return addHeadline(name, true); | ||
294 | + } | ||
295 | + | ||
296 | + private JLabel addHeadline(String name, boolean newline) { | ||
297 | + final JLabel label = new JLabel(name); | ||
298 | + label.setFont(label.getFont().deriveFont(Font.BOLD, 18f)); | ||
299 | + add(label, (newline ? "newline unrelated, " : "") + "split, span"); | ||
300 | + add(new JSeparator(), "growx, wrap related"); | ||
301 | + return label; | ||
302 | + } | ||
303 | + | ||
304 | + private class DotLabel extends JLabel { | ||
305 | + | ||
306 | + private boolean[] state = new boolean[WWPreferences.WIIMOTES]; | ||
307 | + | ||
308 | + public DotLabel(String name) { | ||
309 | + setText(name); | ||
310 | + setHorizontalAlignment(SwingConstants.CENTER); | ||
311 | + setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
312 | + } | ||
313 | + | ||
314 | + public void update(Wiimote wiimote, boolean state) { | ||
315 | + if (this.state[wiimote.getId() - 1] != state) { | ||
316 | + this.state[wiimote.getId() - 1] = state; | ||
317 | + repaint(); | ||
318 | + } | ||
319 | + } | ||
320 | + | ||
321 | + @Override | ||
322 | + protected void paintComponent(Graphics g) { | ||
323 | + final int n = Math.max(1, dh.getNumberOfConnectedWiimotes()); | ||
324 | + for (int i = 1; i <= n; i++) { | ||
325 | + g.setColor(state[i-1] ? WiimoteIcon.COLORS[i-1] : SystemColor.textInactiveText); | ||
326 | + g.fillRect(0, (i-1)*this.getHeight()/n, this.getWidth(), this.getHeight()/n); | ||
327 | + } | ||
328 | + super.paintComponent(g); | ||
329 | + } | ||
330 | + | ||
331 | + } | ||
332 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MainPanel.java~
0 → 100644
@@ -0,0 +1,384 @@ | @@ -0,0 +1,384 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import java.awt.Color; | ||
29 | +import java.awt.Font; | ||
30 | +import java.awt.Graphics; | ||
31 | +import java.awt.Point; | ||
32 | +import java.awt.SystemColor; | ||
33 | +import java.awt.event.ActionEvent; | ||
34 | +import java.awt.event.ActionListener; | ||
35 | +import java.awt.event.WindowEvent; | ||
36 | +import java.awt.event.WindowFocusListener; | ||
37 | +import java.util.Map; | ||
38 | +import java.util.logging.Level; | ||
39 | + | ||
40 | +import javax.swing.BorderFactory; | ||
41 | +import javax.swing.ButtonGroup; | ||
42 | +import javax.swing.ImageIcon; | ||
43 | +import javax.swing.JButton; | ||
44 | +import javax.swing.JCheckBox; | ||
45 | +import javax.swing.JLabel; | ||
46 | +import javax.swing.JOptionPane; | ||
47 | +import javax.swing.JPanel; | ||
48 | +import javax.swing.JProgressBar; | ||
49 | +import javax.swing.JRadioButton; | ||
50 | +import javax.swing.JSeparator; | ||
51 | +import javax.swing.SwingConstants; | ||
52 | + | ||
53 | +import net.miginfocom.swing.MigLayout; | ||
54 | + | ||
55 | +import org.jdesktop.application.Action; | ||
56 | +import org.jdesktop.application.Application; | ||
57 | +import org.jdesktop.application.ResourceMap; | ||
58 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler; | ||
59 | +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard; | ||
60 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
61 | +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
62 | +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; | ||
63 | +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener; | ||
64 | +import org.uweschmidt.wiimote.whiteboard.ds.IRDot; | ||
65 | +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote; | ||
66 | +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences; | ||
67 | +import org.uweschmidt.wiimote.whiteboard.util.Util; | ||
68 | + | ||
69 | +@SuppressWarnings("serial") | ||
70 | +public class MainPanel extends JPanel implements WiimoteDataListener, CalibrationEventListener { | ||
71 | + | ||
72 | + private static final ImageIcon CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/ok.png")); | ||
73 | + private static final ImageIcon NOT_CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/warning.png")); | ||
74 | + | ||
75 | + private static final WWPreferences prefs = WWPreferences.getPreferences(); | ||
76 | + | ||
77 | + private DotLabel[] dotLabel = new DotLabel[4]; | ||
78 | + private JProgressBar[] batteryLevel = new JProgressBar[WWPreferences.WIIMOTES]; | ||
79 | + private JButton[] resetButton = new JButton[WWPreferences.WIIMOTES]; | ||
80 | + private WiimoteIcon[] wiimoteIcon = new WiimoteIcon[WWPreferences.WIIMOTES]; | ||
81 | + private JLabel[] statusLabel = new JLabel[WWPreferences.WIIMOTES]; | ||
82 | + private JCheckBox cursorControl; | ||
83 | + private JRadioButton moveMouse, leftClick; | ||
84 | + private JButton calibrationButton, cameraButton /*,warpedButton, calibrationInfoButton*/; | ||
85 | + private ScreenSelector screenSelector; | ||
86 | + | ||
87 | + private boolean notifiedLowBattery = false; | ||
88 | +// private boolean donePack = false; | ||
89 | + | ||
90 | + private Wiimote[] wiimotes = new Wiimote[WWPreferences.WIIMOTES]; | ||
91 | + | ||
92 | + private WiimoteDataHandler dh; | ||
93 | + private WiimoteCalibration calibration; | ||
94 | + private ResourceMap r = Util.getResourceMap(MainPanel.class); | ||
95 | + | ||
96 | + public MainPanel(WiimoteDataHandler dh, WiimoteCalibration calibration) { | ||
97 | + this.dh = dh; | ||
98 | + this.calibration = calibration; | ||
99 | + | ||
100 | + dh.addWiimoteDataListener(this); | ||
101 | + calibration.addCalibrationEventListener(this); | ||
102 | + | ||
103 | + createComponents(); | ||
104 | + | ||
105 | + getValues(); | ||
106 | + update(); | ||
107 | + } | ||
108 | + | ||
109 | + public void getValues() { | ||
110 | + cursorControl.setSelected(dh.isCursorControl()); | ||
111 | +// rightClick.setSelected(prefs.isRightClick()); | ||
112 | + leftClick.setSelected(prefs.isLeftClick()); | ||
113 | + moveMouse.setSelected(!prefs.isLeftClick()); | ||
114 | + } | ||
115 | + | ||
116 | + public void calibrationEvent(CalibrationEvent e) { | ||
117 | + switch (e) { | ||
118 | + case FINISHED: | ||
119 | + case LOADED: | ||
120 | + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION); | ||
121 | + case STARTED: | ||
122 | + case SCREEN_CHANGED: | ||
123 | + case ABORTED: | ||
124 | + update(); | ||
125 | + break; | ||
126 | + } | ||
127 | + } | ||
128 | + | ||
129 | + public void batteryLevel(Wiimote wiimote, double level) { | ||
130 | + batteryLevel[wiimote.getId()-1].setValue((int) Math.round(level * 100)); | ||
131 | + batteryLevel[wiimote.getId()-1].setString(r.getString("batteryLevel", level * 100)); | ||
132 | + | ||
133 | + if (!notifiedLowBattery && prefs.isLowBatteryWarning() && dh.isConnected(wiimote) && level <= .05) { | ||
134 | + notifiedLowBattery = true; | ||
135 | + WiimoteWhiteboard.getLogger().log(Level.WARNING, r.getString("lowBattery")); | ||
136 | + new Thread(new Runnable() { | ||
137 | + public void run() { | ||
138 | + JOptionPane.showMessageDialog(null, r.getString("lowBattery"), WiimoteWhiteboard.getProperty("id"), JOptionPane.WARNING_MESSAGE); | ||
139 | + } | ||
140 | + }).start(); | ||
141 | + } | ||
142 | + } | ||
143 | + | ||
144 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
145 | + for (int i = 0; i < lights.length; i++) { | ||
146 | + dotLabel[i].update(wiimote, lights[i] != null); | ||
147 | + } | ||
148 | + } | ||
149 | + | ||
150 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
151 | + } | ||
152 | + | ||
153 | + public void wiimoteConnected(Wiimote wiimote) { | ||
154 | + wiimotes[wiimote.getId()-1] = wiimote; | ||
155 | + | ||
156 | + if (wiimote.getId() > 1) { | ||
157 | + for (int i = 0; i < wiimote.getId(); i++) { | ||
158 | + wiimoteIcon[i].setVisible(true); | ||
159 | + } | ||
160 | + } | ||
161 | + statusLabel[wiimote.getId()-1].setVisible(true); | ||
162 | + | ||
163 | +// Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack(); | ||
164 | + | ||
165 | + batteryLevel[wiimote.getId()-1].setVisible(true); | ||
166 | + resetButton[wiimote.getId()-1].setVisible(true); | ||
167 | + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION); | ||
168 | + update(); | ||
169 | + } | ||
170 | + | ||
171 | + public void wiimoteDisconnected(Wiimote wiimote) { | ||
172 | + if (wiimote.getId() != 1) batteryLevel[wiimote.getId()-1].setVisible(false); | ||
173 | + if (wiimote.getId() != 1) wiimoteIcon[wiimote.getId()-1].setVisible(false); | ||
174 | + if (wiimote.getId() != 1) resetButton[wiimote.getId()-1].setVisible(false); | ||
175 | + if (wiimote.getId() != 1) statusLabel[wiimote.getId()-1].setVisible(false); | ||
176 | + update(); | ||
177 | +// Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack(); | ||
178 | +// WiimoteWhiteboard.getLogger().log(Level.SEVERE, r.getString("disconnected", id)); | ||
179 | + JOptionPane.showMessageDialog(null, r.getString("disconnected", wiimote.getId()), WiimoteWhiteboard.getProperty("id"), JOptionPane.ERROR_MESSAGE); | ||
180 | + Application.getInstance(WiimoteWhiteboard.class).exit(); | ||
181 | + } | ||
182 | + | ||
183 | + | ||
184 | + /* | ||
185 | + * UPDATE UI WIDGETS | ||
186 | + */ | ||
187 | + | ||
188 | + @Action | ||
189 | + public void update() { | ||
190 | + calibrationButton.setEnabled(dh.isConnected()); | ||
191 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
192 | + resetButton[i].setEnabled(dh.isConnected(wiimotes[i])); | ||
193 | + wiimoteIcon[i].displayConnected(dh.isConnected(wiimotes[i])); | ||
194 | + if (dh.isConnected(wiimotes[i])) { | ||
195 | + boolean calibrated = calibration.isCalibrated(wiimotes[i]); | ||
196 | + statusLabel[i].setText(r.getString(calibrated ? "calibrated" : "notCalibrated")); | ||
197 | + statusLabel[i].setIcon(calibrated ? CALIBRATED : NOT_CALIBRATED); | ||
198 | + } | ||
199 | + } | ||
200 | + cameraButton.setEnabled(dh.isConnected()); | ||
201 | +// warpedButton.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes())); | ||
202 | + screenSelector.setEnabled(dh.isConnected() && !calibration.inProgress()); | ||
203 | + | ||
204 | + if (!dh.isConnected()) { | ||
205 | + batteryLevel[0].setString(r.getString("searching")); | ||
206 | + batteryLevel[0].setValue(0); | ||
207 | + batteryLevel[0].setToolTipText(Util.getResourceMap(MainPanel.class).getString("batteryLevelBar.toolTipText")); | ||
208 | + } else { | ||
209 | + batteryLevel[0].setToolTipText(null); | ||
210 | + } | ||
211 | + | ||
212 | + cursorControl.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes())); | ||
213 | + if (!cursorControl.isEnabled()) | ||
214 | + cursorControl.setSelected(false); | ||
215 | + | ||
216 | + moveMouse.setEnabled(cursorControl.isSelected()); | ||
217 | + leftClick.setEnabled(cursorControl.isSelected()); | ||
218 | +// rightClick.setEnabled(cursorControl.isSelected() && leftClick.isSelected()); | ||
219 | + | ||
220 | + dh.setCursorControl(cursorControl.isSelected()); | ||
221 | + prefs.setLeftClick(leftClick.isSelected()); | ||
222 | +// prefs.setRightClick(/*rightClick.isEnabled() && */rightClick.isSelected()); | ||
223 | + } | ||
224 | + | ||
225 | + /* | ||
226 | + * MAIN PANEL | ||
227 | + */ | ||
228 | + | ||
229 | + private void createComponents() { | ||
230 | + setLayout(new MigLayout("nocache, hidemode 3, gap 0", "[fill]")); | ||
231 | + | ||
232 | + addHeadline(r.getString("wiimoteHeadline"), false); | ||
233 | + | ||
234 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
235 | + add(wiimoteIcon[i] = new WiimoteIcon(i+1), "split"); | ||
236 | + if (i > 0) wiimoteIcon[i].setVisible(false); | ||
237 | + } | ||
238 | + | ||
239 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
240 | + add(batteryLevel[i] = Util.newComponent(JProgressBar.class, "batteryLevelBar"), (i == 0 ? "newline related/2, " : "") + "split"); | ||
241 | + if (i > 0) batteryLevel[i].setVisible(false); | ||
242 | + } | ||
243 | + | ||
244 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
245 | + add(statusLabel[i] = Util.newComponent(JLabel.class, "statusLabel"), (i == 0 ? "newline related/2, split, " : "") + "sg, h 16!, center"); | ||
246 | + statusLabel[i].setFont(statusLabel[i].getFont().deriveFont(10f)); | ||
247 | + if (i > 0) statusLabel[i].setVisible(false); | ||
248 | + } | ||
249 | + | ||
250 | + String gap = Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "0" : "related/2"; | ||
251 | + for (int i = 0; i < WWPreferences.WIIMOTES; i++) { | ||
252 | + final int j = i; | ||
253 | + add(resetButton[i] = Util.newComponent(JButton.class, "resetCameraButton"), (i == 0 ? "newline "+gap+", split, " : "") + ""); | ||
254 | + resetButton[i].putClientProperty("JButton.buttonType", "textured"); | ||
255 | + resetButton[i].putClientProperty("JComponent.sizeVariant", "small"); | ||
256 | + resetButton[i].addActionListener(new ActionListener() { | ||
257 | + public void actionPerformed(ActionEvent e) { | ||
258 | + try { | ||
259 | + dh.enableIR(wiimotes[j]); | ||
260 | + } catch (Exception e1) { | ||
261 | + e1.printStackTrace(); | ||
262 | + } | ||
263 | + } | ||
264 | + }); | ||
265 | + if (i > 0) resetButton[i].setVisible(false); | ||
266 | + } | ||
267 | + | ||
268 | + add(new JSeparator(), String.format("newline %s, span, growx, wrap related", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "related/3" : "related")); | ||
269 | + | ||
270 | + add(Util.newComponent(JLabel.class, "visibleDotsLabel"), "split" + (Util.MAC_OS_X ? ", gapleft 4" : "")); | ||
271 | + add(dotLabel[0] = new DotLabel("1"), "w 18, h 18"); | ||
272 | + add(dotLabel[1] = new DotLabel("2"), "w 18, h 18"); | ||
273 | + add(dotLabel[2] = new DotLabel("3"), "w 18, h 18"); | ||
274 | + add(dotLabel[3] = new DotLabel("4"), "w 18, h 18, wrap related" + (Util.MAC_OS_X ? ", gapright 4" : "")); | ||
275 | + | ||
276 | + add(cameraButton = new JButton(Util.getAction(new CameraMonitor(dh), "monitor")), ""); | ||
277 | + cameraButton.putClientProperty("JButton.buttonType", "textured"); | ||
278 | + | ||
279 | + // CALIBRATION | ||
280 | + | ||
281 | + addHeadline(r.getString("calibrationHeadline")); | ||
282 | + | ||
283 | +// add(warpedButton = new JButton(SC.getAction(new WarpedMonitor(dh, calibration), "monitor")), "wrap"); | ||
284 | + | ||
285 | + final JButton infoButton = new JButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info")); | ||
286 | +// final JToggleButton infoButton = new JToggleButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info")); | ||
287 | + infoButton.putClientProperty("JButton.buttonType", "textured"); | ||
288 | + infoButton.putClientProperty("JComponent.sizeVariant", "small"); | ||
289 | + add(infoButton, "wrap related"); | ||
290 | +// add(new JSeparator(), "span, growx, wrap"); | ||
291 | + | ||
292 | + | ||
293 | + add(screenSelector = new ScreenSelector(calibration, dh), "align center, grow 0, wrap related"); | ||
294 | + | ||
295 | + add(calibrationButton = Util.newComponent(JButton.class, "calibrationButton"), ""); | ||
296 | + calibrationButton.putClientProperty("JButton.buttonType", "textured"); | ||
297 | + calibrationButton.addActionListener(new ActionListener() { | ||
298 | + public void actionPerformed(ActionEvent e) { | ||
299 | + calibration.start(dh.getConnectedWiimotes()); | ||
300 | + } | ||
301 | + }); | ||
302 | + | ||
303 | + // MOUSE CONTROL | ||
304 | + | ||
305 | + addHeadline(r.getString("mouseControlHeadline")); | ||
306 | + | ||
307 | + add(cursorControl = Util.newComponent(JCheckBox.class, "cursorControl"), "wrap related"); | ||
308 | + add(moveMouse = Util.newComponent(JRadioButton.class, "moveMouse"), "pad 0 20 0 0, wmin pref+20, wrap related"); | ||
309 | + add(leftClick = Util.newComponent(JRadioButton.class, "leftClick"), "pad 0 20 0 0, wmin pref+20, wrap"); | ||
310 | +// add(rightClick = SC.newComponent(JCheckBox.class, "rightClick"), "pad 0 20 0 0, wrap"); | ||
311 | + | ||
312 | +// add(new JSeparator(), "wrap"); | ||
313 | +// final JButton exitButton = new JButton(SC.getAction(Application.getInstance(), "quitApp")); | ||
314 | +// add(exitButton, "wrap"); | ||
315 | + | ||
316 | + ButtonGroup group = new ButtonGroup(); | ||
317 | + group.add(moveMouse); | ||
318 | + group.add(leftClick); | ||
319 | + | ||
320 | + cursorControl.addActionListener(Util.getAction(this, "update")); | ||
321 | + moveMouse.addActionListener(Util.getAction(this, "update")); | ||
322 | + leftClick.addActionListener(Util.getAction(this, "update")); | ||
323 | +// rightClick.addActionListener(SC.getAction(this, "update")); | ||
324 | + | ||
325 | + // fixes issue that components stay grayed out although they're enabled | ||
326 | + // (mac os x), only happens when mainFrame doesn't have focus on connect | ||
327 | + // workaround for windows: pack() once frame gains focus, due to | ||
328 | + // incorrect height apparently caused by non-resizability | ||
329 | + Application.getInstance(WiimoteWhiteboard.class).getMainFrame().addWindowFocusListener(new WindowFocusListener() { | ||
330 | + public void windowGainedFocus(WindowEvent e) { | ||
331 | + updateUI(); | ||
332 | +// if (!Util.MAC_OS_X && !donePack) { | ||
333 | +// donePack = true; | ||
334 | +// Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack(); | ||
335 | +// } | ||
336 | + } | ||
337 | + public void windowLostFocus(WindowEvent e) {} | ||
338 | + }); | ||
339 | + | ||
340 | + Util.getResourceMap(MainPanel.class).injectComponents(this); | ||
341 | + } | ||
342 | + | ||
343 | + private JLabel addHeadline(String name) { | ||
344 | + return addHeadline(name, true); | ||
345 | + } | ||
346 | + | ||
347 | + private JLabel addHeadline(String name, boolean newline) { | ||
348 | + final JLabel label = new JLabel(name); | ||
349 | + label.setFont(label.getFont().deriveFont(Font.BOLD, 18f)); | ||
350 | + add(label, (newline ? "newline unrelated, " : "") + "split, span"); | ||
351 | + add(new JSeparator(), "growx, wrap related"); | ||
352 | + return label; | ||
353 | + } | ||
354 | + | ||
355 | + private class DotLabel extends JLabel { | ||
356 | + | ||
357 | + private boolean[] state = new boolean[WWPreferences.WIIMOTES]; | ||
358 | + | ||
359 | + public DotLabel(String name) { | ||
360 | + setText(name); | ||
361 | + setHorizontalAlignment(SwingConstants.CENTER); | ||
362 | + setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
363 | + } | ||
364 | + | ||
365 | + public void update(Wiimote wiimote, boolean state) { | ||
366 | + if (this.state[wiimote.getId() - 1] != state) { | ||
367 | + this.state[wiimote.getId() - 1] = state; | ||
368 | + repaint(); | ||
369 | + } | ||
370 | + } | ||
371 | + | ||
372 | + @Override | ||
373 | + protected void paintComponent(Graphics g) { | ||
374 | + final int n = Math.max(1, dh.getNumberOfConnectedWiimotes()); | ||
375 | + for (int i = 1; i <= n; i++) { | ||
376 | + g.setColor(state[i-1] ? WiimoteIcon.COLORS[i-1] : SystemColor.textInactiveText); | ||
377 | + g.fillRect(0, (i-1)*this.getHeight()/n, this.getWidth(), this.getHeight()/n); | ||
378 | +// g.fillRect((i-1)*this.getWidth()/n, 0, this.getWidth()/n, this.getHeight()); | ||
379 | + } | ||
380 | + super.paintComponent(g); | ||
381 | + } | ||
382 | + | ||
383 | + } | ||
384 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MenuBar.java
0 → 100644
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Toolkit; | ||
4 | +import java.awt.event.KeyEvent; | ||
5 | + | ||
6 | +import javax.swing.JMenu; | ||
7 | +import javax.swing.JMenuBar; | ||
8 | +import javax.swing.JMenuItem; | ||
9 | +import javax.swing.KeyStroke; | ||
10 | + | ||
11 | +import org.jdesktop.application.Application; | ||
12 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
13 | +import org.mote.wiimote.whiteboard.util.Util; | ||
14 | + | ||
15 | +@SuppressWarnings("serial") | ||
16 | +public class MenuBar extends JMenuBar { | ||
17 | + | ||
18 | + public MenuBar(PreferencesWindow pf, AboutWindow af, /*HelpHandler hh*/, LogWindow lw) { | ||
19 | + JMenu menu; | ||
20 | + JMenuItem item; | ||
21 | + | ||
22 | + if (!Util.MAC_OS_X) { | ||
23 | + menu = new JMenu(Util.getResourceMap(MenuBar.class).getString("editMenu")); | ||
24 | + menu.add(new JMenuItem(Util.getAction(pf, "preferences"))); | ||
25 | + add(menu); | ||
26 | + } | ||
27 | + | ||
28 | + //menu = new JMenu(Util.getResourceMap(HelpHandler.class).getString("help")); | ||
29 | + | ||
30 | + //menu.add(item = new JMenuItem(Util.getAction(hh, "help"))); | ||
31 | + if (Util.MAC_OS_X) | ||
32 | + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, KeyEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); | ||
33 | + | ||
34 | + //menu.addSeparator(); | ||
35 | + | ||
36 | + //if (!Util.MAC_OS_X) | ||
37 | + // menu.add(new JMenuItem(Util.getAction(af, "about"))); | ||
38 | + | ||
39 | + //menu.add(new JMenuItem(Util.getAction(lw, "log"))); | ||
40 | + | ||
41 | + //menu.addSeparator(); | ||
42 | + | ||
43 | + //menu.add(new JMenuItem(Util.getAction(Application.getInstance(WiimoteWhiteboard.class), "donate"))); | ||
44 | + | ||
45 | + add(menu); | ||
46 | + } | ||
47 | + | ||
48 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MenuBar.java~
0 → 100644
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Toolkit; | ||
4 | +import java.awt.event.KeyEvent; | ||
5 | + | ||
6 | +import javax.swing.JMenu; | ||
7 | +import javax.swing.JMenuBar; | ||
8 | +import javax.swing.JMenuItem; | ||
9 | +import javax.swing.KeyStroke; | ||
10 | + | ||
11 | +import org.jdesktop.application.Application; | ||
12 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
13 | +import org.mote.wiimote.whiteboard.util.Util; | ||
14 | + | ||
15 | +@SuppressWarnings("serial") | ||
16 | +public class MenuBar extends JMenuBar { | ||
17 | + | ||
18 | + public MenuBar(PreferencesWindow pf, AboutWindow af, /*HelpHandler hh*/, LogWindow lw) { | ||
19 | + JMenu menu; | ||
20 | + JMenuItem item; | ||
21 | + | ||
22 | + if (!Util.MAC_OS_X) { | ||
23 | + menu = new JMenu(Util.getResourceMap(MenuBar.class).getString("editMenu")); | ||
24 | + menu.add(new JMenuItem(Util.getAction(pf, "preferences"))); | ||
25 | + add(menu); | ||
26 | + } | ||
27 | + | ||
28 | + //menu = new JMenu(Util.getResourceMap(HelpHandler.class).getString("help")); | ||
29 | + | ||
30 | + //menu.add(item = new JMenuItem(Util.getAction(hh, "help"))); | ||
31 | + if (Util.MAC_OS_X) | ||
32 | + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, KeyEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); | ||
33 | + | ||
34 | + //menu.addSeparator(); | ||
35 | + | ||
36 | + //if (!Util.MAC_OS_X) | ||
37 | + // menu.add(new JMenuItem(Util.getAction(af, "about"))); | ||
38 | + | ||
39 | + //menu.add(new JMenuItem(Util.getAction(lw, "log"))); | ||
40 | + | ||
41 | + //menu.addSeparator(); | ||
42 | + | ||
43 | + //menu.add(new JMenuItem(Util.getAction(Application.getInstance(WiimoteWhiteboard.class), "donate"))); | ||
44 | + | ||
45 | + add(menu); | ||
46 | + } | ||
47 | + | ||
48 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/PreferencesWindow.java
0 → 100644
@@ -0,0 +1,342 @@ | @@ -0,0 +1,342 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | +import java.awt.BorderLayout; | ||
3 | +import java.awt.FlowLayout; | ||
4 | +import java.awt.Insets; | ||
5 | +import java.awt.event.ActionEvent; | ||
6 | +import java.awt.event.ActionListener; | ||
7 | +import java.awt.event.ItemEvent; | ||
8 | +import java.awt.event.ItemListener; | ||
9 | +import java.awt.event.WindowEvent; | ||
10 | +import java.awt.event.WindowFocusListener; | ||
11 | +import java.net.InetAddress; | ||
12 | +import java.net.UnknownHostException; | ||
13 | +import java.util.Dictionary; | ||
14 | +import java.util.Hashtable; | ||
15 | + | ||
16 | +import javax.swing.BorderFactory; | ||
17 | +import javax.swing.ButtonGroup; | ||
18 | +import javax.swing.DefaultComboBoxModel; | ||
19 | +import javax.swing.JButton; | ||
20 | +import javax.swing.JCheckBox; | ||
21 | +import javax.swing.JComboBox; | ||
22 | +import javax.swing.JDialog; | ||
23 | +import javax.swing.JLabel; | ||
24 | +import javax.swing.JOptionPane; | ||
25 | +import javax.swing.JPanel; | ||
26 | +import javax.swing.JRadioButton; | ||
27 | +import javax.swing.JSeparator; | ||
28 | +import javax.swing.JSlider; | ||
29 | +import javax.swing.JTabbedPane; | ||
30 | +import javax.swing.JTextField; | ||
31 | +import javax.swing.UIManager; | ||
32 | +import javax.swing.border.Border; | ||
33 | +import javax.swing.border.TitledBorder; | ||
34 | +import javax.swing.event.ChangeEvent; | ||
35 | +import javax.swing.event.ChangeListener; | ||
36 | + | ||
37 | +import net.miginfocom.swing.MigLayout; | ||
38 | + | ||
39 | +import org.jdesktop.application.Action; | ||
40 | +import org.jdesktop.application.Application; | ||
41 | +import org.jdesktop.application.ResourceMap; | ||
42 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
43 | +import org.mote.wiimote.whiteboard.mouse.DefaultControlStrategy; | ||
44 | +import org.mote.wiimote.whiteboard.mouse.TouchpadControlStrategy; | ||
45 | +import org.mote.wiimote.whiteboard.mouse.smoothing.AdaptiveExponentialSmoothing; | ||
46 | +import org.mote.wiimote.whiteboard.mouse.smoothing.NoSmoothing; | ||
47 | +import org.mote.wiimote.whiteboard.mouse.smoothing.SimpleMovingAverage; | ||
48 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
49 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences.LocaleWrapper; | ||
50 | +import org.mote.wiimote.whiteboard.util.Util; | ||
51 | + | ||
52 | +@SuppressWarnings("serial") | ||
53 | +public class PreferencesWindow extends JDialog { | ||
54 | + | ||
55 | + private final static WWPreferences prefs = WWPreferences.getPreferences(); | ||
56 | + private final static ResourceMap r = Util.getResourceMap(PreferencesWindow.class); | ||
57 | + | ||
58 | + private JSlider delaySlider; | ||
59 | + private JTextField tuioHost; | ||
60 | + private JButton defaultsButton; | ||
61 | + private JCheckBox batteryWarning, checkForUpdates, tuioEnable, mouseSmoothing, touchpadMode, rightClicks, assistDoubleClicks; | ||
62 | + private JRadioButton staticSmoothing, adaptiveSmoothing; | ||
63 | + private JComboBox languages; | ||
64 | + private JTabbedPane tabbedPane; | ||
65 | + private boolean donePack = false; | ||
66 | + | ||
67 | + public PreferencesWindow(final MainPanel mp, final HelpHandler hh) { | ||
68 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), r.getString("preferences.Action.text")); | ||
69 | + | ||
70 | + Border aquaBorder = UIManager.getBorder("TitledBorder.aquaVariant"); | ||
71 | + if (aquaBorder != null) UIManager.put("TitledBorder.border", aquaBorder); | ||
72 | + | ||
73 | + // create panels | ||
74 | + tabbedPane = new JTabbedPane(); | ||
75 | + JPanel generalPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : "")); | ||
76 | + JPanel mousePanel = new JPanel(new MigLayout(Util.MAC_OS_X ? String.format("insets para-10 para %s para", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "para-10" : "para") : "")); | ||
77 | + JPanel tuioPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : "")); | ||
78 | + generalPanel.setOpaque(false); | ||
79 | + mousePanel.setOpaque(false); | ||
80 | + tuioPanel.setOpaque(false); | ||
81 | + tabbedPane.addTab(r.getString("generalTab"), generalPanel); | ||
82 | + tabbedPane.addTab(r.getString("mouseTab"), mousePanel); | ||
83 | + tabbedPane.addTab(r.getString("tuioTab"), tuioPanel); | ||
84 | + | ||
85 | + ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(8, 10, 10, 10)); | ||
86 | + add(tabbedPane, BorderLayout.CENTER); | ||
87 | + | ||
88 | + /* | ||
89 | + * GENERAL PANEL | ||
90 | + */ | ||
91 | + | ||
92 | + // check for updates | ||
93 | + generalPanel.add(checkForUpdates = Util.newComponent(JCheckBox.class, "checkForUpdates"), "wrap"); | ||
94 | + checkForUpdates.addActionListener(new ActionListener() { | ||
95 | + public void actionPerformed(ActionEvent arg0) { | ||
96 | + prefs.setCheckForUpdates(checkForUpdates.isSelected()); | ||
97 | + } | ||
98 | + }); | ||
99 | + | ||
100 | + // low battery warning | ||
101 | + generalPanel.add(batteryWarning = Util.newComponent(JCheckBox.class, "batteryWarning"), "wrap"); | ||
102 | + batteryWarning.addActionListener(new ActionListener() { | ||
103 | + public void actionPerformed(ActionEvent arg0) { | ||
104 | + prefs.setLowBatteryWarning(batteryWarning.isSelected()); | ||
105 | + } | ||
106 | + }); | ||
107 | + | ||
108 | + generalPanel.add(new JSeparator(), "split, span, pushx, growx, wrap"); | ||
109 | + | ||
110 | + generalPanel.add(Util.newComponent(JLabel.class, "language"), "split, gapbottom 3, gapleft 6"); | ||
111 | + generalPanel.add(languages = Util.newComponent(JComboBox.class, "languageBox"), "wrap"); | ||
112 | + languages.setModel(new DefaultComboBoxModel(WWPreferences.LANGUAGES)); | ||
113 | + languages.addItemListener(new ItemListener() { | ||
114 | + public void itemStateChanged(ItemEvent e) { | ||
115 | + if (e.getStateChange() == ItemEvent.SELECTED) { | ||
116 | + prefs.setLanguage(((LocaleWrapper)languages.getSelectedItem()).getLocaleString()); | ||
117 | + } | ||
118 | + } | ||
119 | + }); | ||
120 | + generalPanel.add(Util.newComponent(JLabel.class, "languageRestartLabel"), "split, span, w 225, gapleft 6"); | ||
121 | + | ||
122 | + /* | ||
123 | + * MOUSE CONTROL PANEL | ||
124 | + */ | ||
125 | + | ||
126 | + // touchpad mode | ||
127 | + mousePanel.add(touchpadMode = Util.newComponent(JCheckBox.class, "touchpadMode"), "wrap"); | ||
128 | + touchpadMode.addActionListener(new ActionListener() { | ||
129 | + public void actionPerformed(ActionEvent arg0) { | ||
130 | + prefs.setCursorControl(touchpadMode.isSelected() ? TouchpadControlStrategy.class.getName() : DefaultControlStrategy.class.getName()); | ||
131 | + } | ||
132 | + }); | ||
133 | + | ||
134 | + mousePanel.add(assistDoubleClicks = Util.newComponent(JCheckBox.class, "assistDoubleClicks"), "wrap"); | ||
135 | + assistDoubleClicks.addActionListener(new ActionListener() { | ||
136 | + public void actionPerformed(ActionEvent arg0) { | ||
137 | + prefs.setAssistDoubleClicks(assistDoubleClicks.isSelected()); | ||
138 | + } | ||
139 | + }); | ||
140 | + | ||
141 | + // mouse smoothing | ||
142 | + final ButtonGroup smoothingGroup = new ButtonGroup(); | ||
143 | + mousePanel.add(mouseSmoothing = Util.newComponent(JCheckBox.class, "mouseSmoothing"), "split"); | ||
144 | + mouseSmoothing.addActionListener(new ActionListener() { | ||
145 | + public void actionPerformed(ActionEvent arg0) { | ||
146 | + staticSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
147 | + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
148 | + if (mouseSmoothing.isSelected()) { | ||
149 | + if (smoothingGroup.getSelection() == null) | ||
150 | + adaptiveSmoothing.doClick(); | ||
151 | + else { | ||
152 | + if (adaptiveSmoothing.isSelected()) adaptiveSmoothing.doClick(); | ||
153 | + if (staticSmoothing.isSelected()) staticSmoothing.doClick(); | ||
154 | + } | ||
155 | + } else { | ||
156 | + prefs.setMouseSmoothing(NoSmoothing.class.getName()); | ||
157 | + } | ||
158 | + } | ||
159 | + }); | ||
160 | + | ||
161 | + mousePanel.add(staticSmoothing = Util.newComponent(JRadioButton.class, "staticSmoothing")); | ||
162 | + staticSmoothing.addActionListener(new ActionListener() { | ||
163 | + public void actionPerformed(ActionEvent e) { | ||
164 | + prefs.setMouseSmoothing(SimpleMovingAverage.class.getName()); | ||
165 | + } | ||
166 | + }); | ||
167 | + smoothingGroup.add(staticSmoothing); | ||
168 | + | ||
169 | + mousePanel.add(adaptiveSmoothing = Util.newComponent(JRadioButton.class, "adaptiveSmoothing")); | ||
170 | + adaptiveSmoothing.addActionListener(new ActionListener() { | ||
171 | + public void actionPerformed(ActionEvent e) { | ||
172 | + prefs.setMouseSmoothing(AdaptiveExponentialSmoothing.class.getName()); | ||
173 | + } | ||
174 | + }); | ||
175 | + smoothingGroup.add(adaptiveSmoothing); | ||
176 | + | ||
177 | + | ||
178 | + | ||
179 | + mousePanel.add(new JSeparator(), "newline, split, span, pushx, growx, wrap"); | ||
180 | + | ||
181 | + // right clicks | ||
182 | + mousePanel.add(rightClicks = Util.newComponent(JCheckBox.class, "rightClicks"), "wrap"); | ||
183 | + rightClicks.addActionListener(new ActionListener() { | ||
184 | + public void actionPerformed(ActionEvent arg0) { | ||
185 | + prefs.setRightClick(rightClicks.isSelected()); | ||
186 | + } | ||
187 | + }); | ||
188 | + | ||
189 | + // right click activation delay | ||
190 | + JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); | ||
191 | + wrapper.setOpaque(false); | ||
192 | + final TitledBorder tb = BorderFactory.createTitledBorder(null, r.getString("rightClickDelay"), TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION, new JLabel().getFont().deriveFont(11f)); | ||
193 | + wrapper.setBorder(tb); | ||
194 | + delaySlider = Util.newComponent(JSlider.class, "delaySlider"); | ||
195 | + Dictionary<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>(); | ||
196 | + labelTable.put(500, new JLabel("\u00bd")); | ||
197 | + labelTable.put(1000, new JLabel("1")); | ||
198 | + labelTable.put(2000, new JLabel("2")); | ||
199 | + labelTable.put(3000, new JLabel("3")); | ||
200 | + delaySlider.setLabelTable(labelTable); | ||
201 | + delaySlider.addChangeListener(new ChangeListener() { | ||
202 | + public void stateChanged(ChangeEvent e) { | ||
203 | + if (!delaySlider.getValueIsAdjusting() && isVisible()) { | ||
204 | + prefs.setRightClickDelay(delaySlider.getValue()); | ||
205 | + } | ||
206 | + } | ||
207 | + }); | ||
208 | + Insets tbInsets = tb.getBorderInsets(wrapper); | ||
209 | + int tbWidth = tb.getMinimumSize(wrapper).width-tbInsets.left-tbInsets.right+(Util.MAC_OS_X_LEOPARD_OR_HIGHER ? 0 : 20); | ||
210 | + wrapper.add(delaySlider); | ||
211 | + mousePanel.add(wrapper, "center, growx, w " +tbWidth); | ||
212 | + | ||
213 | + /* | ||
214 | + * TUIO/OSC PANEL | ||
215 | + */ | ||
216 | + | ||
217 | + // enable tuio | ||
218 | + tuioPanel.add(tuioEnable = Util.newComponent(JCheckBox.class, "tuioEnable"), "wrap"); | ||
219 | + tuioEnable.addActionListener(new ActionListener() { | ||
220 | + public void actionPerformed(ActionEvent arg0) { | ||
221 | + if (tuioEnable.isSelected()) { | ||
222 | + String[] s = tuioHost.getText().split(":"); | ||
223 | + String errorTitle = null; | ||
224 | + if ((s.length == 1 && s[0].length() == 0) || s.length > 2) { | ||
225 | + errorTitle = r.getString("tuioInvalidFormat"); | ||
226 | + } else { | ||
227 | + try { | ||
228 | + int port = 3333; | ||
229 | + if (s.length == 2) { | ||
230 | + port = Integer.valueOf(s[1]); | ||
231 | + if (port < 0 || port > 0xFFFF) { | ||
232 | + throw new NumberFormatException(); | ||
233 | + } | ||
234 | + } | ||
235 | + InetAddress.getByName(s[0]); | ||
236 | + | ||
237 | + prefs.setTuioPort(port); | ||
238 | + prefs.setTuioHost(s[0]); | ||
239 | + prefs.setTuioEnabled(true); | ||
240 | + } catch (NumberFormatException e) { | ||
241 | + errorTitle = r.getString("tuioInvalidPort", s[1]); | ||
242 | + } catch (UnknownHostException e) { | ||
243 | + errorTitle = r.getString("tuioInvalidHost", s[0]); | ||
244 | + } | ||
245 | + } | ||
246 | + | ||
247 | + if (errorTitle != null) { | ||
248 | + JOptionPane.showMessageDialog(PreferencesWindow.this, r.getString("tuioErrorMessage"), errorTitle, JOptionPane.ERROR_MESSAGE); | ||
249 | + } | ||
250 | + | ||
251 | + } else { | ||
252 | + prefs.setTuioEnabled(false); | ||
253 | + } | ||
254 | + update(); | ||
255 | + } | ||
256 | + }); | ||
257 | + | ||
258 | + // tuio host | ||
259 | + tuioPanel.add(tuioHost = Util.newComponent(JTextField.class, "tuioHost"), "growx, pushx, wrap"); | ||
260 | + | ||
261 | + | ||
262 | + JPanel bottomPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets 0 2 0 2, gap 0" : "insets i 0 0 0, gap 0")); | ||
263 | + add(bottomPanel, BorderLayout.SOUTH); | ||
264 | + | ||
265 | + bottomPanel.add(defaultsButton = Util.newComponent(JButton.class, "resetButton")); | ||
266 | + defaultsButton.addActionListener(new ActionListener() { | ||
267 | + public void actionPerformed(ActionEvent e) { | ||
268 | + prefs.reset(); | ||
269 | + mp.update(); | ||
270 | + update(); | ||
271 | + } | ||
272 | + }); | ||
273 | + | ||
274 | + JButton helpButton = new JButton(Util.getAction(hh, "help")); | ||
275 | + bottomPanel.add(helpButton, "push, right"); | ||
276 | + if (Util.MAC_OS_X_LEOPARD_OR_HIGHER) { | ||
277 | + helpButton.setText(""); | ||
278 | + helpButton.putClientProperty("JButton.buttonType", "help"); | ||
279 | + } else { | ||
280 | + helpButton.setText(Util.getResourceMap(HelpHandler.class).getString("help")); | ||
281 | + } | ||
282 | + | ||
283 | + Util.getResourceMap(PreferencesWindow.class).injectComponents(this); | ||
284 | + | ||
285 | + pack(); | ||
286 | + setResizable(false); | ||
287 | + | ||
288 | + if (Util.WINDOWS) { | ||
289 | + addWindowFocusListener(new WindowFocusListener() { | ||
290 | + public void windowGainedFocus(WindowEvent e) { | ||
291 | + if (!donePack) { | ||
292 | + donePack = true; | ||
293 | + pack(); | ||
294 | + Util.placeDialogWindow(PreferencesWindow.this, getWidth(), getHeight()); | ||
295 | + } | ||
296 | + } | ||
297 | + public void windowLostFocus(WindowEvent e) {} | ||
298 | + }); | ||
299 | + } | ||
300 | + } | ||
301 | + | ||
302 | + private void update() { | ||
303 | + checkForUpdates.setSelected(prefs.checkForUpdates()); | ||
304 | + batteryWarning.setSelected(prefs.isLowBatteryWarning()); | ||
305 | + rightClicks.setSelected(prefs.isRightClick()); | ||
306 | + assistDoubleClicks.setSelected(prefs.assistDoubleClicks()); | ||
307 | + delaySlider.setValue((int)prefs.getRightClickDelay()); | ||
308 | + tuioEnable.setSelected(prefs.isTuioEnabled()); | ||
309 | + tuioHost.setText(String.format("%s:%d", prefs.getTuioHost(), prefs.getTuioPort())); | ||
310 | + tuioHost.setEnabled(!tuioEnable.isSelected()); | ||
311 | + tuioHost.setToolTipText(tuioHost.isEnabled() ? Util.getResourceMap(PreferencesWindow.class).getString("tuioHost.toolTipText") : r.getString("tuioDisableToEdit")); | ||
312 | + | ||
313 | + touchpadMode.setSelected(TouchpadControlStrategy.class.getName().equals(prefs.getCursorControl())); | ||
314 | + | ||
315 | + mouseSmoothing.setSelected(!NoSmoothing.class.getName().equals(prefs.getMouseSmoothing())); | ||
316 | + adaptiveSmoothing.setSelected(true); | ||
317 | + staticSmoothing.setSelected(SimpleMovingAverage.class.getName().equals(prefs.getMouseSmoothing())); | ||
318 | + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
319 | + staticSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
320 | + | ||
321 | + String lang = prefs.getLanguage(); | ||
322 | + for (int i = 0; i < languages.getItemCount(); i++) { | ||
323 | + LocaleWrapper lw = (LocaleWrapper)languages.getItemAt(i); | ||
324 | + if (lang.equals(lw.getLocaleString())) { | ||
325 | + languages.setSelectedIndex(i); | ||
326 | + break; | ||
327 | + } | ||
328 | + } | ||
329 | + } | ||
330 | + | ||
331 | + @Action | ||
332 | + public void preferences() { | ||
333 | + if (!isVisible()) { | ||
334 | + update(); | ||
335 | + pack(); | ||
336 | + | ||
337 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
338 | + } | ||
339 | + setVisible(true); | ||
340 | + } | ||
341 | + | ||
342 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/PreferencesWindow.java~
0 → 100644
@@ -0,0 +1,396 @@ | @@ -0,0 +1,396 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | +import java.awt.BorderLayout; | ||
28 | +import java.awt.FlowLayout; | ||
29 | +import java.awt.Insets; | ||
30 | +import java.awt.event.ActionEvent; | ||
31 | +import java.awt.event.ActionListener; | ||
32 | +import java.awt.event.ItemEvent; | ||
33 | +import java.awt.event.ItemListener; | ||
34 | +import java.awt.event.WindowEvent; | ||
35 | +import java.awt.event.WindowFocusListener; | ||
36 | +import java.net.InetAddress; | ||
37 | +import java.net.UnknownHostException; | ||
38 | +import java.util.Dictionary; | ||
39 | +import java.util.Hashtable; | ||
40 | + | ||
41 | +import javax.swing.BorderFactory; | ||
42 | +import javax.swing.ButtonGroup; | ||
43 | +import javax.swing.DefaultComboBoxModel; | ||
44 | +import javax.swing.JButton; | ||
45 | +import javax.swing.JCheckBox; | ||
46 | +import javax.swing.JComboBox; | ||
47 | +import javax.swing.JDialog; | ||
48 | +import javax.swing.JLabel; | ||
49 | +import javax.swing.JOptionPane; | ||
50 | +import javax.swing.JPanel; | ||
51 | +import javax.swing.JRadioButton; | ||
52 | +import javax.swing.JSeparator; | ||
53 | +import javax.swing.JSlider; | ||
54 | +import javax.swing.JTabbedPane; | ||
55 | +import javax.swing.JTextField; | ||
56 | +import javax.swing.UIManager; | ||
57 | +import javax.swing.border.Border; | ||
58 | +import javax.swing.border.TitledBorder; | ||
59 | +import javax.swing.event.ChangeEvent; | ||
60 | +import javax.swing.event.ChangeListener; | ||
61 | + | ||
62 | +import net.miginfocom.swing.MigLayout; | ||
63 | + | ||
64 | +import org.jdesktop.application.Action; | ||
65 | +import org.jdesktop.application.Application; | ||
66 | +import org.jdesktop.application.ResourceMap; | ||
67 | +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard; | ||
68 | +import org.uweschmidt.wiimote.whiteboard.mouse.DefaultControlStrategy; | ||
69 | +import org.uweschmidt.wiimote.whiteboard.mouse.TouchpadControlStrategy; | ||
70 | +import org.uweschmidt.wiimote.whiteboard.mouse.smoothing.AdaptiveExponentialSmoothing; | ||
71 | +import org.uweschmidt.wiimote.whiteboard.mouse.smoothing.NoSmoothing; | ||
72 | +import org.uweschmidt.wiimote.whiteboard.mouse.smoothing.SimpleMovingAverage; | ||
73 | +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences; | ||
74 | +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences.LocaleWrapper; | ||
75 | +import org.uweschmidt.wiimote.whiteboard.util.Util; | ||
76 | + | ||
77 | +@SuppressWarnings("serial") | ||
78 | +public class PreferencesWindow extends JDialog { | ||
79 | + | ||
80 | + private final static WWPreferences prefs = WWPreferences.getPreferences(); | ||
81 | + private final static ResourceMap r = Util.getResourceMap(PreferencesWindow.class); | ||
82 | + | ||
83 | + private JSlider delaySlider; | ||
84 | + private JTextField tuioHost; | ||
85 | + private JButton defaultsButton; | ||
86 | + private JCheckBox batteryWarning, checkForUpdates, tuioEnable, mouseSmoothing, touchpadMode, rightClicks, assistDoubleClicks; | ||
87 | + private JRadioButton staticSmoothing, adaptiveSmoothing; | ||
88 | +// private JRadioButton[] wiimoteNumberButtons = new JRadioButton[WWPreferences.WIIMOTES]; | ||
89 | + private JComboBox languages; | ||
90 | + private JTabbedPane tabbedPane; | ||
91 | + private boolean donePack = false; | ||
92 | + | ||
93 | + public PreferencesWindow(final MainPanel mp, final HelpHandler hh) { | ||
94 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), r.getString("preferences.Action.text")); | ||
95 | + | ||
96 | + // use NSBox-like TitledBorder if available (Leopard) | ||
97 | + Border aquaBorder = UIManager.getBorder("TitledBorder.aquaVariant"); | ||
98 | + if (aquaBorder != null) UIManager.put("TitledBorder.border", aquaBorder); | ||
99 | + | ||
100 | + // create panels | ||
101 | + tabbedPane = new JTabbedPane(); | ||
102 | + JPanel generalPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : "")); | ||
103 | + // FIXME bottom insets too large, but only in French on Leopard?! | ||
104 | + JPanel mousePanel = new JPanel(new MigLayout(Util.MAC_OS_X ? String.format("insets para-10 para %s para", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "para-10" : "para") : "")); | ||
105 | + JPanel tuioPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : "")); | ||
106 | + generalPanel.setOpaque(false); | ||
107 | + mousePanel.setOpaque(false); | ||
108 | + tuioPanel.setOpaque(false); | ||
109 | + tabbedPane.addTab(r.getString("generalTab"), generalPanel); | ||
110 | + tabbedPane.addTab(r.getString("mouseTab"), mousePanel); | ||
111 | + tabbedPane.addTab(r.getString("tuioTab"), tuioPanel); | ||
112 | + | ||
113 | + ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(8, 10, 10, 10)); | ||
114 | + add(tabbedPane, BorderLayout.CENTER); | ||
115 | + | ||
116 | + /* | ||
117 | + * GENERAL PANEL | ||
118 | + */ | ||
119 | + | ||
120 | + // check for updates | ||
121 | + generalPanel.add(checkForUpdates = Util.newComponent(JCheckBox.class, "checkForUpdates"), "wrap"); | ||
122 | + checkForUpdates.addActionListener(new ActionListener() { | ||
123 | + public void actionPerformed(ActionEvent arg0) { | ||
124 | + prefs.setCheckForUpdates(checkForUpdates.isSelected()); | ||
125 | + } | ||
126 | + }); | ||
127 | + | ||
128 | + // low battery warning | ||
129 | + generalPanel.add(batteryWarning = Util.newComponent(JCheckBox.class, "batteryWarning"), "wrap"); | ||
130 | + batteryWarning.addActionListener(new ActionListener() { | ||
131 | + public void actionPerformed(ActionEvent arg0) { | ||
132 | + prefs.setLowBatteryWarning(batteryWarning.isSelected()); | ||
133 | + } | ||
134 | + }); | ||
135 | + | ||
136 | + generalPanel.add(new JSeparator(), "split, span, pushx, growx, wrap"); | ||
137 | + | ||
138 | + generalPanel.add(Util.newComponent(JLabel.class, "language"), "split, gapbottom 3, gapleft 6"); | ||
139 | + generalPanel.add(languages = Util.newComponent(JComboBox.class, "languageBox"), "wrap"); | ||
140 | +// languages.putClientProperty("JComboBox.isSquare", Boolean.TRUE); | ||
141 | +// languages.putClientProperty("JComboBox.isPopDown", Boolean.TRUE); | ||
142 | + languages.setModel(new DefaultComboBoxModel(WWPreferences.LANGUAGES)); | ||
143 | + languages.addItemListener(new ItemListener() { | ||
144 | + public void itemStateChanged(ItemEvent e) { | ||
145 | + if (e.getStateChange() == ItemEvent.SELECTED) { | ||
146 | + prefs.setLanguage(((LocaleWrapper)languages.getSelectedItem()).getLocaleString()); | ||
147 | + } | ||
148 | + } | ||
149 | + }); | ||
150 | + generalPanel.add(Util.newComponent(JLabel.class, "languageRestartLabel"), "split, span, w 225, gapleft 6"); | ||
151 | + | ||
152 | +// // number of wiimotes | ||
153 | +// generalPanel.add(Util.newComponent(JLabel.class, "numberOfWiimotesLabel")); | ||
154 | +// ButtonGroup bg = new ButtonGroup(); | ||
155 | +// for (int i = 1; i <= WWPreferences.WIIMOTES; i++) { | ||
156 | +// final int j = i-1; | ||
157 | +// bg.add(wiimoteNumberButtons[j] = new JRadioButton(String.valueOf(i))); | ||
158 | +// wiimoteNumberButtons[j].setOpaque(false); | ||
159 | +// wiimoteNumberButtons[j].addActionListener(new ActionListener() { | ||
160 | +// public void actionPerformed(ActionEvent e) { | ||
161 | +// prefs.setNumberOfWiimotes(j+1); | ||
162 | +// } | ||
163 | +// }); | ||
164 | +// generalPanel.add(wiimoteNumberButtons[j], i == 1 ? "split" : ""); | ||
165 | +// } | ||
166 | +// generalPanel.add(Util.newComponent(JLabel.class, "numberOfWiimotesExplLabel"), "newline, split, span, center, w 290"); | ||
167 | + | ||
168 | + /* | ||
169 | + * MOUSE CONTROL PANEL | ||
170 | + */ | ||
171 | + | ||
172 | + // touchpad mode | ||
173 | + mousePanel.add(touchpadMode = Util.newComponent(JCheckBox.class, "touchpadMode"), "wrap"); | ||
174 | + touchpadMode.addActionListener(new ActionListener() { | ||
175 | + public void actionPerformed(ActionEvent arg0) { | ||
176 | + prefs.setCursorControl(touchpadMode.isSelected() ? TouchpadControlStrategy.class.getName() : DefaultControlStrategy.class.getName()); | ||
177 | + } | ||
178 | + }); | ||
179 | + | ||
180 | + // assist double clicks | ||
181 | + mousePanel.add(assistDoubleClicks = Util.newComponent(JCheckBox.class, "assistDoubleClicks"), "wrap"); | ||
182 | + assistDoubleClicks.addActionListener(new ActionListener() { | ||
183 | + public void actionPerformed(ActionEvent arg0) { | ||
184 | + prefs.setAssistDoubleClicks(assistDoubleClicks.isSelected()); | ||
185 | + } | ||
186 | + }); | ||
187 | + | ||
188 | + // mouse smoothing | ||
189 | + final ButtonGroup smoothingGroup = new ButtonGroup(); | ||
190 | + mousePanel.add(mouseSmoothing = Util.newComponent(JCheckBox.class, "mouseSmoothing"), "split"); | ||
191 | + mouseSmoothing.addActionListener(new ActionListener() { | ||
192 | + public void actionPerformed(ActionEvent arg0) { | ||
193 | + staticSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
194 | + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
195 | + if (mouseSmoothing.isSelected()) { | ||
196 | + if (smoothingGroup.getSelection() == null) | ||
197 | + adaptiveSmoothing.doClick(); | ||
198 | + else { | ||
199 | + // trigger actionlistener | ||
200 | + if (adaptiveSmoothing.isSelected()) adaptiveSmoothing.doClick(); | ||
201 | + if (staticSmoothing.isSelected()) staticSmoothing.doClick(); | ||
202 | + } | ||
203 | + } else { | ||
204 | + prefs.setMouseSmoothing(NoSmoothing.class.getName()); | ||
205 | + } | ||
206 | + } | ||
207 | + }); | ||
208 | + | ||
209 | + mousePanel.add(staticSmoothing = Util.newComponent(JRadioButton.class, "staticSmoothing")); | ||
210 | + staticSmoothing.addActionListener(new ActionListener() { | ||
211 | + public void actionPerformed(ActionEvent e) { | ||
212 | + prefs.setMouseSmoothing(SimpleMovingAverage.class.getName()); | ||
213 | + } | ||
214 | + }); | ||
215 | + smoothingGroup.add(staticSmoothing); | ||
216 | + | ||
217 | + mousePanel.add(adaptiveSmoothing = Util.newComponent(JRadioButton.class, "adaptiveSmoothing")); | ||
218 | + adaptiveSmoothing.addActionListener(new ActionListener() { | ||
219 | + public void actionPerformed(ActionEvent e) { | ||
220 | + prefs.setMouseSmoothing(AdaptiveExponentialSmoothing.class.getName()); | ||
221 | + } | ||
222 | + }); | ||
223 | + smoothingGroup.add(adaptiveSmoothing); | ||
224 | + | ||
225 | + | ||
226 | + | ||
227 | + mousePanel.add(new JSeparator(), "newline, split, span, pushx, growx, wrap"); | ||
228 | + | ||
229 | + // right clicks | ||
230 | + mousePanel.add(rightClicks = Util.newComponent(JCheckBox.class, "rightClicks"), "wrap"); | ||
231 | + rightClicks.addActionListener(new ActionListener() { | ||
232 | + public void actionPerformed(ActionEvent arg0) { | ||
233 | + prefs.setRightClick(rightClicks.isSelected()); | ||
234 | + } | ||
235 | + }); | ||
236 | + | ||
237 | + // right click activation delay | ||
238 | + JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); | ||
239 | + wrapper.setOpaque(false); | ||
240 | + final TitledBorder tb = BorderFactory.createTitledBorder(null, r.getString("rightClickDelay"), TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION, new JLabel().getFont().deriveFont(11f)); | ||
241 | + wrapper.setBorder(tb); | ||
242 | + delaySlider = Util.newComponent(JSlider.class, "delaySlider"); | ||
243 | + Dictionary<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>(); | ||
244 | + labelTable.put(500, new JLabel("\u00bd")); | ||
245 | + labelTable.put(1000, new JLabel("1")); | ||
246 | + labelTable.put(2000, new JLabel("2")); | ||
247 | + labelTable.put(3000, new JLabel("3")); | ||
248 | + delaySlider.setLabelTable(labelTable); | ||
249 | + delaySlider.addChangeListener(new ChangeListener() { | ||
250 | + public void stateChanged(ChangeEvent e) { | ||
251 | + if (!delaySlider.getValueIsAdjusting() && isVisible()) { | ||
252 | + prefs.setRightClickDelay(delaySlider.getValue()); | ||
253 | + } | ||
254 | + } | ||
255 | + }); | ||
256 | + Insets tbInsets = tb.getBorderInsets(wrapper); | ||
257 | + int tbWidth = tb.getMinimumSize(wrapper).width-tbInsets.left-tbInsets.right+(Util.MAC_OS_X_LEOPARD_OR_HIGHER ? 0 : 20); | ||
258 | + wrapper.add(delaySlider); | ||
259 | + mousePanel.add(wrapper, "center, growx, w " +tbWidth); | ||
260 | + | ||
261 | + /* | ||
262 | + * TUIO/OSC PANEL | ||
263 | + */ | ||
264 | + | ||
265 | + // enable tuio | ||
266 | + tuioPanel.add(tuioEnable = Util.newComponent(JCheckBox.class, "tuioEnable"), "wrap"); | ||
267 | + tuioEnable.addActionListener(new ActionListener() { | ||
268 | + public void actionPerformed(ActionEvent arg0) { | ||
269 | + if (tuioEnable.isSelected()) { | ||
270 | + String[] s = tuioHost.getText().split(":"); | ||
271 | + String errorTitle = null; | ||
272 | + if ((s.length == 1 && s[0].length() == 0) || s.length > 2) { | ||
273 | + errorTitle = r.getString("tuioInvalidFormat"); | ||
274 | + } else { | ||
275 | + try { | ||
276 | + int port = 3333; | ||
277 | + if (s.length == 2) { | ||
278 | + port = Integer.valueOf(s[1]); | ||
279 | + if (port < 0 || port > 0xFFFF) { | ||
280 | + throw new NumberFormatException(); | ||
281 | + } | ||
282 | + } | ||
283 | + InetAddress.getByName(s[0]); | ||
284 | + | ||
285 | + prefs.setTuioPort(port); | ||
286 | + prefs.setTuioHost(s[0]); | ||
287 | + prefs.setTuioEnabled(true); | ||
288 | + } catch (NumberFormatException e) { | ||
289 | + errorTitle = r.getString("tuioInvalidPort", s[1]); | ||
290 | + } catch (UnknownHostException e) { | ||
291 | + errorTitle = r.getString("tuioInvalidHost", s[0]); | ||
292 | + } | ||
293 | + } | ||
294 | + | ||
295 | + if (errorTitle != null) { | ||
296 | + JOptionPane.showMessageDialog(PreferencesWindow.this, r.getString("tuioErrorMessage"), errorTitle, JOptionPane.ERROR_MESSAGE); | ||
297 | + } | ||
298 | + | ||
299 | + } else { | ||
300 | + prefs.setTuioEnabled(false); | ||
301 | + } | ||
302 | + update(); | ||
303 | + } | ||
304 | + }); | ||
305 | + | ||
306 | + // tuio host | ||
307 | + tuioPanel.add(tuioHost = Util.newComponent(JTextField.class, "tuioHost"), "growx, pushx, wrap"); | ||
308 | + | ||
309 | + | ||
310 | + JPanel bottomPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets 0 2 0 2, gap 0" : "insets i 0 0 0, gap 0")); | ||
311 | + add(bottomPanel, BorderLayout.SOUTH); | ||
312 | + | ||
313 | + bottomPanel.add(defaultsButton = Util.newComponent(JButton.class, "resetButton")); | ||
314 | +// defaultsButton.putClientProperty("JButton.buttonType", "textured"); | ||
315 | + defaultsButton.addActionListener(new ActionListener() { | ||
316 | + public void actionPerformed(ActionEvent e) { | ||
317 | + prefs.reset(); | ||
318 | + // re-set currently chosen mouse control settings | ||
319 | + // (probably not perceived as persistent preferences by user) | ||
320 | + mp.update(); | ||
321 | + update(); | ||
322 | + } | ||
323 | + }); | ||
324 | + | ||
325 | + JButton helpButton = new JButton(Util.getAction(hh, "help")); | ||
326 | + bottomPanel.add(helpButton, "push, right"); | ||
327 | + if (Util.MAC_OS_X_LEOPARD_OR_HIGHER) { | ||
328 | + helpButton.setText(""); | ||
329 | + helpButton.putClientProperty("JButton.buttonType", "help"); | ||
330 | + } else { | ||
331 | + helpButton.setText(Util.getResourceMap(HelpHandler.class).getString("help")); | ||
332 | + } | ||
333 | + | ||
334 | + Util.getResourceMap(PreferencesWindow.class).injectComponents(this); | ||
335 | + | ||
336 | + pack(); | ||
337 | + setResizable(false); | ||
338 | + | ||
339 | + if (Util.WINDOWS) { | ||
340 | + addWindowFocusListener(new WindowFocusListener() { | ||
341 | + public void windowGainedFocus(WindowEvent e) { | ||
342 | + if (!donePack) { | ||
343 | + donePack = true; | ||
344 | + pack(); | ||
345 | + Util.placeDialogWindow(PreferencesWindow.this, getWidth(), getHeight()); | ||
346 | + } | ||
347 | + } | ||
348 | + public void windowLostFocus(WindowEvent e) {} | ||
349 | + }); | ||
350 | + } | ||
351 | + } | ||
352 | + | ||
353 | + private void update() { | ||
354 | + checkForUpdates.setSelected(prefs.checkForUpdates()); | ||
355 | + batteryWarning.setSelected(prefs.isLowBatteryWarning()); | ||
356 | + rightClicks.setSelected(prefs.isRightClick()); | ||
357 | + assistDoubleClicks.setSelected(prefs.assistDoubleClicks()); | ||
358 | + delaySlider.setValue((int)prefs.getRightClickDelay()); | ||
359 | + tuioEnable.setSelected(prefs.isTuioEnabled()); | ||
360 | + tuioHost.setText(String.format("%s:%d", prefs.getTuioHost(), prefs.getTuioPort())); | ||
361 | + tuioHost.setEnabled(!tuioEnable.isSelected()); | ||
362 | + tuioHost.setToolTipText(tuioHost.isEnabled() ? Util.getResourceMap(PreferencesWindow.class).getString("tuioHost.toolTipText") : r.getString("tuioDisableToEdit")); | ||
363 | +// wiimoteNumberButtons[prefs.getNumberOfWiimotes()-1].setSelected(true); | ||
364 | + | ||
365 | + touchpadMode.setSelected(TouchpadControlStrategy.class.getName().equals(prefs.getCursorControl())); | ||
366 | + | ||
367 | + mouseSmoothing.setSelected(!NoSmoothing.class.getName().equals(prefs.getMouseSmoothing())); | ||
368 | + adaptiveSmoothing.setSelected(true); | ||
369 | + staticSmoothing.setSelected(SimpleMovingAverage.class.getName().equals(prefs.getMouseSmoothing())); | ||
370 | + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
371 | + staticSmoothing.setEnabled(mouseSmoothing.isSelected()); | ||
372 | + | ||
373 | + String lang = prefs.getLanguage(); | ||
374 | + for (int i = 0; i < languages.getItemCount(); i++) { | ||
375 | + LocaleWrapper lw = (LocaleWrapper)languages.getItemAt(i); | ||
376 | + if (lang.equals(lw.getLocaleString())) { | ||
377 | + languages.setSelectedIndex(i); | ||
378 | + break; | ||
379 | + } | ||
380 | + } | ||
381 | + } | ||
382 | + | ||
383 | + @Action | ||
384 | + public void preferences() { | ||
385 | + if (!isVisible()) { | ||
386 | + update(); | ||
387 | + pack(); | ||
388 | +// if (Util.WINDOWS && !donePack) { | ||
389 | +// setSize(getWidth(), 300); | ||
390 | +// } | ||
391 | + Util.placeDialogWindow(this, getWidth(), getHeight()); | ||
392 | + } | ||
393 | + setVisible(true); | ||
394 | + } | ||
395 | + | ||
396 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/ScreenSelector.java
0 → 100644
@@ -0,0 +1,206 @@ | @@ -0,0 +1,206 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.BasicStroke; | ||
4 | +import java.awt.Color; | ||
5 | +import java.awt.Dimension; | ||
6 | +import java.awt.Graphics; | ||
7 | +import java.awt.Graphics2D; | ||
8 | +import java.awt.GraphicsDevice; | ||
9 | +import java.awt.GraphicsEnvironment; | ||
10 | +import java.awt.Point; | ||
11 | +import java.awt.Rectangle; | ||
12 | +import java.awt.RenderingHints; | ||
13 | +import java.awt.event.ItemEvent; | ||
14 | +import java.awt.event.ItemListener; | ||
15 | +import java.awt.geom.Point2D; | ||
16 | +import java.awt.geom.Rectangle2D; | ||
17 | +import java.util.Iterator; | ||
18 | +import java.util.LinkedList; | ||
19 | +import java.util.List; | ||
20 | +import java.util.Map; | ||
21 | +import java.util.Timer; | ||
22 | +import java.util.TimerTask; | ||
23 | + | ||
24 | +import javax.media.jai.PerspectiveTransform; | ||
25 | +import javax.swing.BorderFactory; | ||
26 | +import javax.swing.ButtonGroup; | ||
27 | +import javax.swing.JPanel; | ||
28 | +import javax.swing.JRadioButton; | ||
29 | +import javax.swing.SwingConstants; | ||
30 | + | ||
31 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler; | ||
32 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
33 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
34 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
35 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
36 | +import org.mote.wiimote.whiteboard.util.Util; | ||
37 | + | ||
38 | +@SuppressWarnings("serial") | ||
39 | +public class ScreenSelector extends JPanel implements WiimoteDataListener { | ||
40 | + | ||
41 | + private static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); | ||
42 | + private static final int MAX_H = 130; | ||
43 | + private static final int MAX_W = 185; | ||
44 | + | ||
45 | + private static final long REPAINT_FREQ = 1000 / 20; | ||
46 | + | ||
47 | + private WiimoteCalibration calibration; | ||
48 | + private List<ScreenBox> screenBoxes = new LinkedList<ScreenBox>(); | ||
49 | + private Point lastCursor = null, cursor = null; | ||
50 | + | ||
51 | + public ScreenSelector(WiimoteCalibration calibration, WiimoteDataHandler dh) { | ||
52 | + super(null); | ||
53 | + this.calibration = calibration; | ||
54 | + dh.addWiimoteDataListener(this); | ||
55 | + | ||
56 | + final GraphicsDevice[] screens = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); | ||
57 | + | ||
58 | + Rectangle r = new Rectangle(); | ||
59 | + for (GraphicsDevice s : screens) { | ||
60 | + r = r.union(s.getDefaultConfiguration().getBounds()); | ||
61 | + } | ||
62 | + | ||
63 | + final int maxH = MAX_H - (screens.length == 1 ? 30 : 0); | ||
64 | + int w = MAX_W; | ||
65 | + int h = (int) Math.round((w * r.getHeight()) / r.getWidth()); | ||
66 | + // if too high | ||
67 | + if (h > maxH) { | ||
68 | + h = maxH; | ||
69 | + w = (int) Math.round((h * r.getWidth()) / r.getHeight()); | ||
70 | + } | ||
71 | + setPreferredSize(new Dimension(w, h)); | ||
72 | + | ||
73 | + PerspectiveTransform t = PerspectiveTransform.getQuadToQuad( | ||
74 | + r.getMinX(), r.getMinY(), r.getMaxX(), r.getMinY(), | ||
75 | + r.getMaxX(), r.getMaxY(), r.getMinX(), r.getMaxY(), | ||
76 | + 0, 0, w, 0, w, h, 0, h); | ||
77 | + | ||
78 | + ButtonGroup bg = new ButtonGroup(); | ||
79 | + for (int i = 0; i < screens.length; i++) { | ||
80 | + Rectangle b = screens[i].getDefaultConfiguration().getBounds(); | ||
81 | + final ScreenBox sb = new ScreenBox(screens[i], i, transformBounds(t, b), screens[i].equals(DEFAULT_SCREEN)); | ||
82 | + bg.add(sb); | ||
83 | + screenBoxes.add(sb); | ||
84 | + add(sb); | ||
85 | + } | ||
86 | + | ||
87 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
88 | + } | ||
89 | + | ||
90 | + private class UpdateTask extends TimerTask { | ||
91 | + @Override | ||
92 | + public void run() { | ||
93 | + if (cursor != lastCursor) { | ||
94 | + for (ScreenBox sb : screenBoxes) { | ||
95 | + if (sb.isSelected() && sb.isEnabled()) { | ||
96 | + lastCursor = cursor; | ||
97 | + sb.repaint(); | ||
98 | + } | ||
99 | + } | ||
100 | + } | ||
101 | + } | ||
102 | + } | ||
103 | + | ||
104 | + private Rectangle transformBounds(PerspectiveTransform t, Rectangle b) { | ||
105 | + Point2D ul = t.transform(new Point2D.Double(b.getMinX(), b.getMinY()), null); | ||
106 | + Point2D ur = t.transform(new Point2D.Double(b.getMaxX(), b.getMinY()), null); | ||
107 | + Point2D ll = t.transform(new Point2D.Double(b.getMinX(), b.getMaxY()), null); | ||
108 | + return new Rectangle2D.Double(ul.getX(), ul.getY(), ul.distance(ur), ul.distance(ll)).getBounds(); | ||
109 | + } | ||
110 | + | ||
111 | + @Override | ||
112 | + public void setEnabled(boolean enabled) { | ||
113 | + super.setEnabled(enabled); | ||
114 | + enableScreenBoxes(enabled); | ||
115 | + } | ||
116 | + | ||
117 | + private class ScreenBox extends JRadioButton { | ||
118 | + private final BasicStroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); | ||
119 | + private static final int DIAMETER = 4; | ||
120 | + private static final int MAX_TRACE = 1000 / (int)REPAINT_FREQ; | ||
121 | + private LinkedList<Point> trace = new LinkedList<Point>(); | ||
122 | + private GraphicsDevice screen; | ||
123 | + private final Rectangle bounds; | ||
124 | + public ScreenBox(GraphicsDevice screen, int i, Rectangle b, boolean selected) { | ||
125 | + super(Util.getResourceMap(ScreenSelector.class).getString("screenText", i+1, (int)screen.getDefaultConfiguration().getBounds().getWidth(), (int)screen.getDefaultConfiguration().getBounds().getHeight())); | ||
126 | + this.screen = screen; | ||
127 | + bounds = screen.getDefaultConfiguration().getBounds(); | ||
128 | + | ||
129 | + setBounds(b); | ||
130 | + setSelected(selected); | ||
131 | + | ||
132 | + setFocusable(false); | ||
133 | + setHorizontalAlignment(SwingConstants.CENTER); | ||
134 | + | ||
135 | + if (!Util.MAC_OS_X) setBorder(BorderFactory.createEtchedBorder()); | ||
136 | + setBorderPainted(true); | ||
137 | + | ||
138 | + addItemListener(new ItemListener() { | ||
139 | + public void itemStateChanged(ItemEvent e) { | ||
140 | + if (e.getStateChange() == ItemEvent.SELECTED) { | ||
141 | + calibration.setScreen(ScreenBox.this.screen); | ||
142 | + } | ||
143 | + } | ||
144 | + }); | ||
145 | + } | ||
146 | + | ||
147 | + @Override | ||
148 | + protected void paintComponent(Graphics g) { | ||
149 | + super.paintComponent(g); | ||
150 | + if (isSelected() && cursor != null) { | ||
151 | + Graphics2D g2d = (Graphics2D)g; | ||
152 | + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
153 | + try { | ||
154 | + | ||
155 | + int x = Math.max(0, Math.min(getWidth(), (int)Math.round(((cursor.x - bounds.x) / bounds.getWidth()) * getWidth()))); | ||
156 | + int y = Math.max(0, Math.min(getHeight(), (int)Math.round(((cursor.y - bounds.y) / bounds.getHeight()) * getHeight()))); | ||
157 | + | ||
158 | + if (trace.size() > MAX_TRACE) | ||
159 | + trace.removeFirst(); | ||
160 | + | ||
161 | + if (!trace.isEmpty()) { | ||
162 | + g2d.setStroke(STROKE); | ||
163 | + int inc = 255/MAX_TRACE, alpha = (MAX_TRACE - trace.size()) * inc; | ||
164 | + Iterator<Point> it = trace.iterator(); | ||
165 | + Point lp = it.next(); | ||
166 | + while (it.hasNext()) { | ||
167 | + Point p = it.next(); | ||
168 | + g2d.setColor(new Color(0,0,255,alpha)); | ||
169 | + g2d.drawLine(lp.x, lp.y, p.x, p.y); | ||
170 | + lp = p; | ||
171 | + alpha += inc; | ||
172 | + } | ||
173 | + g2d.setColor(Color.blue); | ||
174 | + g2d.drawLine(lp.x, lp.y, x, y); | ||
175 | + } | ||
176 | + | ||
177 | + g2d.setColor(Color.blue); | ||
178 | + g2d.fillOval(x-DIAMETER/2, y-DIAMETER/2, DIAMETER, DIAMETER); | ||
179 | + | ||
180 | + trace.addLast(new Point(x,y)); | ||
181 | + } catch (NullPointerException e) { | ||
182 | + trace.clear(); | ||
183 | + } | ||
184 | + } else { | ||
185 | + trace.clear(); | ||
186 | + } | ||
187 | + } | ||
188 | + } | ||
189 | + | ||
190 | + private void enableScreenBoxes(boolean enabled) { | ||
191 | + | ||
192 | + for (ScreenBox b : screenBoxes) | ||
193 | + b.setEnabled(enabled); | ||
194 | + } | ||
195 | + | ||
196 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
197 | + cursor = warped[0]; | ||
198 | + } | ||
199 | + public void batteryLevel(Wiimote wiimote, double level) {} | ||
200 | + public void irLights(Wiimote wiimote, IRDot[] lights) {} | ||
201 | + public void wiimoteConnected(Wiimote wiimote) {} | ||
202 | + public void wiimoteDisconnected(Wiimote wiimote) {} | ||
203 | + | ||
204 | + | ||
205 | + | ||
206 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/ScreenSelector.java~
0 → 100644
@@ -0,0 +1,311 @@ | @@ -0,0 +1,311 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import java.awt.BasicStroke; | ||
29 | +import java.awt.Color; | ||
30 | +import java.awt.Dimension; | ||
31 | +import java.awt.Graphics; | ||
32 | +import java.awt.Graphics2D; | ||
33 | +import java.awt.GraphicsDevice; | ||
34 | +import java.awt.GraphicsEnvironment; | ||
35 | +import java.awt.Point; | ||
36 | +import java.awt.Rectangle; | ||
37 | +import java.awt.RenderingHints; | ||
38 | +import java.awt.event.ItemEvent; | ||
39 | +import java.awt.event.ItemListener; | ||
40 | +import java.awt.geom.Point2D; | ||
41 | +import java.awt.geom.Rectangle2D; | ||
42 | +import java.util.Iterator; | ||
43 | +import java.util.LinkedList; | ||
44 | +import java.util.List; | ||
45 | +import java.util.Map; | ||
46 | +import java.util.Timer; | ||
47 | +import java.util.TimerTask; | ||
48 | + | ||
49 | +import javax.media.jai.PerspectiveTransform; | ||
50 | +import javax.swing.BorderFactory; | ||
51 | +import javax.swing.ButtonGroup; | ||
52 | +import javax.swing.JPanel; | ||
53 | +import javax.swing.JRadioButton; | ||
54 | +import javax.swing.SwingConstants; | ||
55 | + | ||
56 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler; | ||
57 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
58 | +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
59 | +import org.uweschmidt.wiimote.whiteboard.ds.IRDot; | ||
60 | +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote; | ||
61 | +import org.uweschmidt.wiimote.whiteboard.util.Util; | ||
62 | + | ||
63 | +@SuppressWarnings("serial") | ||
64 | +public class ScreenSelector extends JPanel implements WiimoteDataListener { | ||
65 | + | ||
66 | + private static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); | ||
67 | + private static final int MAX_H = 130; | ||
68 | + private static final int MAX_W = 185; | ||
69 | + | ||
70 | + private static final long REPAINT_FREQ = 1000 / 20; | ||
71 | + | ||
72 | + private WiimoteCalibration calibration; | ||
73 | +// private WiimoteDataHandler dh; | ||
74 | + private List<ScreenBox> screenBoxes = new LinkedList<ScreenBox>(); | ||
75 | + private Point lastCursor = null, cursor = null; | ||
76 | + | ||
77 | + public ScreenSelector(WiimoteCalibration calibration, WiimoteDataHandler dh) { | ||
78 | + super(null); | ||
79 | + this.calibration = calibration; | ||
80 | +// this.dh = dh; | ||
81 | + dh.addWiimoteDataListener(this); | ||
82 | + | ||
83 | + final GraphicsDevice[] screens = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); | ||
84 | + | ||
85 | + // calculate maximum screen bounds (virtual device) | ||
86 | + Rectangle r = new Rectangle(); | ||
87 | + for (GraphicsDevice s : screens) { | ||
88 | + r = r.union(s.getDefaultConfiguration().getBounds()); | ||
89 | + } | ||
90 | + | ||
91 | + final int maxH = MAX_H - (screens.length == 1 ? 30 : 0); | ||
92 | + // proportional bounds of panel | ||
93 | + int w = MAX_W; | ||
94 | + int h = (int) Math.round((w * r.getHeight()) / r.getWidth()); | ||
95 | + // if too high | ||
96 | + if (h > maxH) { | ||
97 | + h = maxH; | ||
98 | + w = (int) Math.round((h * r.getWidth()) / r.getHeight()); | ||
99 | + } | ||
100 | + setPreferredSize(new Dimension(w, h)); | ||
101 | + | ||
102 | + // map screen bounds to panel bounds | ||
103 | + PerspectiveTransform t = PerspectiveTransform.getQuadToQuad( | ||
104 | + r.getMinX(), r.getMinY(), r.getMaxX(), r.getMinY(), | ||
105 | + r.getMaxX(), r.getMaxY(), r.getMinX(), r.getMaxY(), | ||
106 | + 0, 0, w, 0, w, h, 0, h); | ||
107 | + | ||
108 | + // TODO temporary until multiple screens are allowed | ||
109 | + ButtonGroup bg = new ButtonGroup(); | ||
110 | + for (int i = 0; i < screens.length; i++) { | ||
111 | + Rectangle b = screens[i].getDefaultConfiguration().getBounds(); | ||
112 | + final ScreenBox sb = new ScreenBox(screens[i], i, transformBounds(t, b), screens[i].equals(DEFAULT_SCREEN)); | ||
113 | + bg.add(sb); | ||
114 | + screenBoxes.add(sb); | ||
115 | + add(sb); | ||
116 | + } | ||
117 | + | ||
118 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
119 | + } | ||
120 | + | ||
121 | + private class UpdateTask extends TimerTask { | ||
122 | + @Override | ||
123 | + public void run() { | ||
124 | + if (cursor != lastCursor) { | ||
125 | + for (ScreenBox sb : screenBoxes) { | ||
126 | + if (sb.isSelected() && sb.isEnabled()) { | ||
127 | + lastCursor = cursor; | ||
128 | + sb.repaint(); | ||
129 | + } | ||
130 | + } | ||
131 | + } | ||
132 | + } | ||
133 | + } | ||
134 | + | ||
135 | + private Rectangle transformBounds(PerspectiveTransform t, Rectangle b) { | ||
136 | + Point2D ul = t.transform(new Point2D.Double(b.getMinX(), b.getMinY()), null); | ||
137 | + Point2D ur = t.transform(new Point2D.Double(b.getMaxX(), b.getMinY()), null); | ||
138 | + Point2D ll = t.transform(new Point2D.Double(b.getMinX(), b.getMaxY()), null); | ||
139 | + return new Rectangle2D.Double(ul.getX(), ul.getY(), ul.distance(ur), ul.distance(ll)).getBounds(); | ||
140 | + } | ||
141 | + | ||
142 | + @Override | ||
143 | + public void setEnabled(boolean enabled) { | ||
144 | + super.setEnabled(enabled); | ||
145 | + enableScreenBoxes(enabled); | ||
146 | + } | ||
147 | + | ||
148 | + // TODO use JToggleButton instead of JRadioButton or JCheckBox | ||
149 | + private class ScreenBox extends JRadioButton { | ||
150 | + private final BasicStroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); | ||
151 | + private static final int DIAMETER = 4; | ||
152 | + private static final int MAX_TRACE = 1000 / (int)REPAINT_FREQ; | ||
153 | + private LinkedList<Point> trace = new LinkedList<Point>(); | ||
154 | + private GraphicsDevice screen; | ||
155 | + private final Rectangle bounds; | ||
156 | +// private final int screenWidth, screenHeight; | ||
157 | + public ScreenBox(GraphicsDevice screen, int i, Rectangle b, boolean selected) { | ||
158 | + super(Util.getResourceMap(ScreenSelector.class).getString("screenText", i+1, (int)screen.getDefaultConfiguration().getBounds().getWidth(), (int)screen.getDefaultConfiguration().getBounds().getHeight())); | ||
159 | + this.screen = screen; | ||
160 | + bounds = screen.getDefaultConfiguration().getBounds(); | ||
161 | +// screenWidth = (int)screen.getDefaultConfiguration().getBounds().getWidth(); | ||
162 | +// screenHeight = (int)screen.getDefaultConfiguration().getBounds().getHeight(); | ||
163 | + | ||
164 | + setBounds(b); | ||
165 | + setSelected(selected); | ||
166 | + | ||
167 | + setFocusable(false); | ||
168 | + setHorizontalAlignment(SwingConstants.CENTER); | ||
169 | + | ||
170 | + if (!Util.MAC_OS_X) setBorder(BorderFactory.createEtchedBorder()); | ||
171 | + setBorderPainted(true); | ||
172 | + | ||
173 | + addItemListener(new ItemListener() { | ||
174 | + public void itemStateChanged(ItemEvent e) { | ||
175 | + if (e.getStateChange() == ItemEvent.SELECTED) { | ||
176 | + calibration.setScreen(ScreenBox.this.screen); | ||
177 | + } | ||
178 | +// enableScreenBoxes(true); | ||
179 | + } | ||
180 | + }); | ||
181 | + } | ||
182 | + | ||
183 | + @Override | ||
184 | + protected void paintComponent(Graphics g) { | ||
185 | + super.paintComponent(g); | ||
186 | + if (isSelected() && cursor != null) { | ||
187 | + Graphics2D g2d = (Graphics2D)g; | ||
188 | + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||
189 | + try { | ||
190 | +// g.setColor(new Color(255,255,255,75)); | ||
191 | +// g.fillRect(0, 0, getWidth(), getHeight()); | ||
192 | + | ||
193 | + int x = Math.max(0, Math.min(getWidth(), (int)Math.round(((cursor.x - bounds.x) / bounds.getWidth()) * getWidth()))); | ||
194 | + int y = Math.max(0, Math.min(getHeight(), (int)Math.round(((cursor.y - bounds.y) / bounds.getHeight()) * getHeight()))); | ||
195 | + | ||
196 | + if (trace.size() > MAX_TRACE) | ||
197 | + trace.removeFirst(); | ||
198 | + | ||
199 | + if (!trace.isEmpty()) { | ||
200 | + g2d.setStroke(STROKE); | ||
201 | + int inc = 255/MAX_TRACE, alpha = (MAX_TRACE - trace.size()) * inc; | ||
202 | + Iterator<Point> it = trace.iterator(); | ||
203 | + Point lp = it.next(); | ||
204 | + while (it.hasNext()) { | ||
205 | + Point p = it.next(); | ||
206 | + g2d.setColor(new Color(0,0,255,alpha)); | ||
207 | + g2d.drawLine(lp.x, lp.y, p.x, p.y); | ||
208 | + lp = p; | ||
209 | + alpha += inc; | ||
210 | + } | ||
211 | + g2d.setColor(Color.blue); | ||
212 | + g2d.drawLine(lp.x, lp.y, x, y); | ||
213 | + } | ||
214 | + | ||
215 | + g2d.setColor(Color.blue); | ||
216 | + g2d.fillOval(x-DIAMETER/2, y-DIAMETER/2, DIAMETER, DIAMETER); | ||
217 | + | ||
218 | + trace.addLast(new Point(x,y)); | ||
219 | + } catch (NullPointerException e) { | ||
220 | + // cursor can be null because of UpdateTask, no problem | ||
221 | + trace.clear(); | ||
222 | + } | ||
223 | + } else { | ||
224 | + trace.clear(); | ||
225 | + } | ||
226 | + } | ||
227 | + } | ||
228 | + | ||
229 | + private void enableScreenBoxes(boolean enabled) { | ||
230 | + | ||
231 | + for (ScreenBox b : screenBoxes) | ||
232 | + b.setEnabled(enabled); | ||
233 | + | ||
234 | +// if (!enabled) { | ||
235 | +// for (ScreenBox b : screenBoxes) | ||
236 | +// b.setEnabled(false); | ||
237 | +// } else { | ||
238 | +// LinkedList<ScreenBox> list = new LinkedList<ScreenBox>(); | ||
239 | +// | ||
240 | +// // enable all screens | ||
241 | +// for (ScreenBox sb : screenBoxes) { | ||
242 | +// sb.setEnabled(true); | ||
243 | +// if (sb.isSelected()) list.add(sb); | ||
244 | +// } | ||
245 | +// | ||
246 | +// // disallow deselection if only screen left | ||
247 | +// if (list.size() == 1) | ||
248 | +// list.getFirst().setEnabled(false); | ||
249 | +// } | ||
250 | + } | ||
251 | + | ||
252 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
253 | + cursor = warped[0]; | ||
254 | + } | ||
255 | + public void batteryLevel(Wiimote wiimote, double level) {} | ||
256 | + public void irLights(Wiimote wiimote, IRDot[] lights) {} | ||
257 | + public void wiimoteConnected(Wiimote wiimote) {} | ||
258 | + public void wiimoteDisconnected(Wiimote wiimote) {} | ||
259 | + | ||
260 | + | ||
261 | +// private class ScreenLabel extends JLabel { | ||
262 | +// | ||
263 | +// private boolean selected; | ||
264 | +// private GraphicsDevice screen; | ||
265 | +// | ||
266 | +// public ScreenLabel(GraphicsDevice screen, int i, Rectangle b, boolean selected) { | ||
267 | +// super(String.format("<html><center>Screen %d<br><small>%d x %d</small></center></html>", i+1, (int)screen.getDefaultConfiguration().getBounds().getWidth(), (int)screen.getDefaultConfiguration().getBounds().getHeight())); | ||
268 | +// this.screen = screen; | ||
269 | +// setSelected(selected); | ||
270 | +// setBounds(b); | ||
271 | +// setOpaque(true); | ||
272 | +// setBorder(BorderFactory.createLineBorder(SystemColor.windowBorder)); | ||
273 | +// setHorizontalAlignment(SwingConstants.CENTER); | ||
274 | +// | ||
275 | +// final ScreenLabel thisLabel = this; | ||
276 | +// addMouseListener(new MouseAdapter() { | ||
277 | +// @Override | ||
278 | +// public void mousePressed(MouseEvent e) { | ||
279 | +// if (thisLabel.isEnabled() && !thisLabel.isSelected()) { | ||
280 | +// calibration.setScreen(thisLabel.screen); | ||
281 | +// thisLabel.setSelected(true); | ||
282 | +// repaint(); | ||
283 | +// for (ScreenLabel l : screenLabels) { | ||
284 | +// if (thisLabel != l) { | ||
285 | +// l.setSelected(false); | ||
286 | +// l.repaint(); | ||
287 | +// } | ||
288 | +// } | ||
289 | +// } | ||
290 | +// } | ||
291 | +// }); | ||
292 | +// } | ||
293 | +// | ||
294 | +// @Override | ||
295 | +// public void setEnabled(boolean enabled) { | ||
296 | +// super.setEnabled(enabled); | ||
297 | +// setForeground(enabled ? SystemColor.textText : SystemColor.textInactiveText); | ||
298 | +// } | ||
299 | +// | ||
300 | +// public void setSelected(boolean selected) { | ||
301 | +// this.selected = selected; | ||
302 | +// setBackground(selected ? SystemColor.textHighlight : SystemColor.window); | ||
303 | +// } | ||
304 | +// | ||
305 | +// public boolean isSelected() { | ||
306 | +// return selected; | ||
307 | +// } | ||
308 | +// | ||
309 | +// } | ||
310 | + | ||
311 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WarpedMonitor.java
0 → 100644
@@ -0,0 +1,137 @@ | @@ -0,0 +1,137 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.BorderLayout; | ||
4 | +import java.awt.Color; | ||
5 | +import java.awt.GraphicsDevice; | ||
6 | +import java.awt.Point; | ||
7 | +import java.awt.Rectangle; | ||
8 | +import java.awt.event.KeyAdapter; | ||
9 | +import java.awt.event.KeyEvent; | ||
10 | +import java.awt.geom.Point2D; | ||
11 | +import java.util.Map; | ||
12 | +import java.util.Timer; | ||
13 | +import java.util.TimerTask; | ||
14 | + | ||
15 | +import javax.swing.BorderFactory; | ||
16 | +import javax.swing.JDialog; | ||
17 | +import javax.swing.JPanel; | ||
18 | + | ||
19 | +import org.jdesktop.application.Action; | ||
20 | +import org.jdesktop.application.Application; | ||
21 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler; | ||
22 | +import org.mote.wiimote.whiteboard.WiimoteWhiteboard; | ||
23 | +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
24 | +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
25 | +import org.mote.wiimote.whiteboard.ds.IRDot; | ||
26 | +import org.mote.wiimote.whiteboard.ds.Wiimote; | ||
27 | +import org.mote.wiimote.whiteboard.preferences.WWPreferences; | ||
28 | +import org.mote.wiimote.whiteboard.util.Util; | ||
29 | + | ||
30 | +@SuppressWarnings("serial") | ||
31 | +public class WarpedMonitor extends JDialog implements WiimoteDataListener { | ||
32 | + | ||
33 | + private static final int REPAINT_FREQ = 1000 / 50; | ||
34 | + static final int RADIUS = 10; | ||
35 | + | ||
36 | + private JPanel canvas; | ||
37 | + private Point2D[][] lights = new Point2D[WWPreferences.WIIMOTES+1][4]; | ||
38 | + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4]; | ||
39 | + private WiimoteCalibration calibration; | ||
40 | + private WiimoteDataHandler dh; | ||
41 | + | ||
42 | + public WarpedMonitor(WiimoteDataHandler dh, final WiimoteCalibration calibration) { | ||
43 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), "Warped Point Monitor"); | ||
44 | + setLayout(new BorderLayout()); | ||
45 | + dh.addWiimoteDataListener(this); | ||
46 | + this.calibration = calibration; | ||
47 | + this.dh = dh; | ||
48 | + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||
49 | + | ||
50 | + canvas = new JPanel(null, true); | ||
51 | + canvas.setBorder(BorderFactory.createLineBorder(Color.black)); | ||
52 | + add(canvas, BorderLayout.CENTER); | ||
53 | + | ||
54 | + setUndecorated(true); | ||
55 | + addKeyListener(new KeyAdapter() { | ||
56 | + @Override | ||
57 | + public void keyPressed(KeyEvent e) { | ||
58 | + if (e.getKeyCode() == KeyEvent.VK_F || e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
59 | + GraphicsDevice screen = calibration.getScreen(); | ||
60 | + if (screen != null) { | ||
61 | + if (screen.getFullScreenWindow() == WarpedMonitor.this) { | ||
62 | + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||
63 | + screen.setFullScreenWindow(null); | ||
64 | + Util.placeDialogWindow(WarpedMonitor.this, 640, 480); | ||
65 | + } else { | ||
66 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) | ||
67 | + WarpedMonitor.this.setVisible(false); | ||
68 | + else { | ||
69 | + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder()); | ||
70 | + screen.setFullScreenWindow(WarpedMonitor.this); | ||
71 | + } | ||
72 | + } | ||
73 | + } | ||
74 | + } | ||
75 | + } | ||
76 | + }); | ||
77 | + | ||
78 | + Util.placeDialogWindow(this, 640, 480); | ||
79 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
80 | + } | ||
81 | + | ||
82 | + @Action | ||
83 | + public void monitor() { | ||
84 | + setVisible(true); | ||
85 | + } | ||
86 | + | ||
87 | + private class UpdateTask extends TimerTask { | ||
88 | + @Override | ||
89 | + public void run() { | ||
90 | + if (isVisible()) { | ||
91 | + for (int i = WWPreferences.WIIMOTES; i >= 0; i--) | ||
92 | + for (int j = 0; j < 4; j++) { | ||
93 | + if (labels[i][j] != null) | ||
94 | + labels[i][j].update(); | ||
95 | + } | ||
96 | + } | ||
97 | + } | ||
98 | + } | ||
99 | + | ||
100 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
101 | + } | ||
102 | + | ||
103 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
104 | + if (isVisible()) { | ||
105 | + Rectangle bounds = calibration.getScreen().getDefaultConfiguration().getBounds(); | ||
106 | + for (int i = 0; i < 4; i++) { | ||
107 | + final Point w = warped[i]; | ||
108 | + this.lights[0][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight()); | ||
109 | + } | ||
110 | + for (Wiimote wiimote : dh.getConnectedWiimotes()) { | ||
111 | + for (int i = 0; i < 4; i++) { | ||
112 | + final Point2D w = calibration.warp(i, wiimote, data); | ||
113 | + this.lights[wiimote.getId()][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight()); | ||
114 | + } | ||
115 | + } | ||
116 | + } | ||
117 | + } | ||
118 | + | ||
119 | + public void batteryLevel(Wiimote wiimote, double level) { | ||
120 | + } | ||
121 | + | ||
122 | + public void wiimoteConnected(Wiimote wiimote) { | ||
123 | + if (wiimote.getId() == 1) | ||
124 | + for (int i = 0; i < 4; i++) | ||
125 | + canvas.add(labels[0][i] = new LightLabel(canvas, lights, 0, i + 1, Color.red)); | ||
126 | + for (int i = 0; i < 4; i++) | ||
127 | + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1)); | ||
128 | + } | ||
129 | + | ||
130 | + public void wiimoteDisconnected(Wiimote wiimote) { | ||
131 | + for (int i = 0; i < 4; i++) { | ||
132 | + canvas.remove(labels[wiimote.getId()][i]); | ||
133 | + labels[wiimote.getId()][i] = null; | ||
134 | + } | ||
135 | + } | ||
136 | + | ||
137 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WarpedMonitor.java~
0 → 100644
@@ -0,0 +1,183 @@ | @@ -0,0 +1,183 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import java.awt.BorderLayout; | ||
29 | +import java.awt.Color; | ||
30 | +import java.awt.GraphicsDevice; | ||
31 | +import java.awt.Point; | ||
32 | +import java.awt.Rectangle; | ||
33 | +import java.awt.event.KeyAdapter; | ||
34 | +import java.awt.event.KeyEvent; | ||
35 | +import java.awt.geom.Point2D; | ||
36 | +import java.util.Map; | ||
37 | +import java.util.Timer; | ||
38 | +import java.util.TimerTask; | ||
39 | + | ||
40 | +import javax.swing.BorderFactory; | ||
41 | +import javax.swing.JDialog; | ||
42 | +import javax.swing.JPanel; | ||
43 | + | ||
44 | +import org.jdesktop.application.Action; | ||
45 | +import org.jdesktop.application.Application; | ||
46 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler; | ||
47 | +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard; | ||
48 | +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; | ||
49 | +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration; | ||
50 | +import org.uweschmidt.wiimote.whiteboard.ds.IRDot; | ||
51 | +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote; | ||
52 | +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences; | ||
53 | +import org.uweschmidt.wiimote.whiteboard.util.Util; | ||
54 | + | ||
55 | +@SuppressWarnings("serial") | ||
56 | +public class WarpedMonitor extends JDialog implements WiimoteDataListener { | ||
57 | + | ||
58 | + private static final int REPAINT_FREQ = 1000 / 50; | ||
59 | + static final int RADIUS = 10; | ||
60 | + | ||
61 | + private JPanel canvas; | ||
62 | + private Point2D[][] lights = new Point2D[WWPreferences.WIIMOTES+1][4]; | ||
63 | + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4]; | ||
64 | + private WiimoteCalibration calibration; | ||
65 | + private WiimoteDataHandler dh; | ||
66 | + | ||
67 | + public WarpedMonitor(WiimoteDataHandler dh, final WiimoteCalibration calibration) { | ||
68 | + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), "Warped Point Monitor"); | ||
69 | + setLayout(new BorderLayout()); | ||
70 | + dh.addWiimoteDataListener(this); | ||
71 | + this.calibration = calibration; | ||
72 | + this.dh = dh; | ||
73 | + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||
74 | + | ||
75 | + canvas = new JPanel(null, true); | ||
76 | + canvas.setBorder(BorderFactory.createLineBorder(Color.black)); | ||
77 | + add(canvas, BorderLayout.CENTER); | ||
78 | + | ||
79 | + setUndecorated(true); | ||
80 | + addKeyListener(new KeyAdapter() { | ||
81 | + @Override | ||
82 | + public void keyPressed(KeyEvent e) { | ||
83 | + if (e.getKeyCode() == KeyEvent.VK_F || e.getKeyCode() == KeyEvent.VK_ESCAPE) { | ||
84 | + GraphicsDevice screen = calibration.getScreen(); | ||
85 | + if (screen != null) { | ||
86 | + if (screen.getFullScreenWindow() == WarpedMonitor.this) { | ||
87 | + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | ||
88 | + screen.setFullScreenWindow(null); | ||
89 | + Util.placeDialogWindow(WarpedMonitor.this, 640, 480); | ||
90 | + } else { | ||
91 | + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) | ||
92 | + WarpedMonitor.this.setVisible(false); | ||
93 | + else { | ||
94 | + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder()); | ||
95 | + screen.setFullScreenWindow(WarpedMonitor.this); | ||
96 | + } | ||
97 | + } | ||
98 | + } | ||
99 | + } | ||
100 | + } | ||
101 | + }); | ||
102 | + | ||
103 | + Util.placeDialogWindow(this, 640, 480); | ||
104 | + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ); | ||
105 | + } | ||
106 | + | ||
107 | + @Action | ||
108 | + public void monitor() { | ||
109 | + setVisible(true); | ||
110 | + } | ||
111 | + | ||
112 | + private class UpdateTask extends TimerTask { | ||
113 | + @Override | ||
114 | + public void run() { | ||
115 | + if (isVisible()) { | ||
116 | + for (int i = WWPreferences.WIIMOTES; i >= 0; i--) | ||
117 | + for (int j = 0; j < 4; j++) { | ||
118 | + if (labels[i][j] != null) | ||
119 | + labels[i][j].update(); | ||
120 | + } | ||
121 | + } | ||
122 | + } | ||
123 | + } | ||
124 | + | ||
125 | + public void irLights(Wiimote wiimote, IRDot[] lights) { | ||
126 | + } | ||
127 | + | ||
128 | + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) { | ||
129 | + if (isVisible()) { | ||
130 | + Rectangle bounds = calibration.getScreen().getDefaultConfiguration().getBounds(); | ||
131 | + for (int i = 0; i < 4; i++) { | ||
132 | + final Point w = warped[i]; | ||
133 | + this.lights[0][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight()); | ||
134 | + } | ||
135 | +// Map<String, Point[]> warpedData = new LinkedHashMap<String, Point[]>(); | ||
136 | + for (Wiimote wiimote : dh.getConnectedWiimotes()) { | ||
137 | +// Point[] pArr = new Point[4]; | ||
138 | + for (int i = 0; i < 4; i++) { | ||
139 | + final Point2D w = calibration.warp(i, wiimote, data); | ||
140 | +// pArr[i] = w; | ||
141 | + this.lights[wiimote.getId()][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight()); | ||
142 | + } | ||
143 | +// warpedData.put(address, pArr); | ||
144 | + } | ||
145 | +// | ||
146 | +// Point[][] cluster = PointClusterer.cluster(warpedData); | ||
147 | +// for (int i = 0; i < cluster.length; i++) { | ||
148 | +// Point[] c = cluster[i]; | ||
149 | +// double x = 0, y = 0; | ||
150 | +// for (Point d : c) { | ||
151 | +// x += d.getX(); | ||
152 | +// y += d.getY(); | ||
153 | +// } | ||
154 | +// final Point2D w = new Point2D.Double(x/c.length, y/c.length); | ||
155 | +// this.lights[0][i] = new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight()); | ||
156 | +//// System.out.println(this.lights[0][i]); | ||
157 | +// } | ||
158 | +// for (int i = cluster.length; i < 4; i++) | ||
159 | +// this.lights[0][i] = null; | ||
160 | + | ||
161 | + | ||
162 | + } | ||
163 | + } | ||
164 | + | ||
165 | + public void batteryLevel(Wiimote wiimote, double level) { | ||
166 | + } | ||
167 | + | ||
168 | + public void wiimoteConnected(Wiimote wiimote) { | ||
169 | + if (wiimote.getId() == 1) | ||
170 | + for (int i = 0; i < 4; i++) | ||
171 | + canvas.add(labels[0][i] = new LightLabel(canvas, lights, 0, i + 1, Color.red)); | ||
172 | + for (int i = 0; i < 4; i++) | ||
173 | + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1)); | ||
174 | + } | ||
175 | + | ||
176 | + public void wiimoteDisconnected(Wiimote wiimote) { | ||
177 | + for (int i = 0; i < 4; i++) { | ||
178 | + canvas.remove(labels[wiimote.getId()][i]); | ||
179 | + labels[wiimote.getId()][i] = null; | ||
180 | + } | ||
181 | + } | ||
182 | + | ||
183 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WiimoteIcon.java
0 → 100644
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +package org.mote.wiimote.whiteboard.gui; | ||
2 | + | ||
3 | +import java.awt.Color; | ||
4 | +import java.awt.SystemColor; | ||
5 | + | ||
6 | +import javax.swing.BorderFactory; | ||
7 | +import javax.swing.JLabel; | ||
8 | +import javax.swing.JPanel; | ||
9 | + | ||
10 | +import net.miginfocom.swing.MigLayout; | ||
11 | + | ||
12 | +@SuppressWarnings("serial") | ||
13 | +public class WiimoteIcon extends JPanel { | ||
14 | + | ||
15 | + public static final Color[] COLORS = { Color.white, Color.pink, Color.orange, Color.green }; | ||
16 | + private JLabel idLabel; | ||
17 | + | ||
18 | + public WiimoteIcon(int id) { | ||
19 | + setBackground(COLORS[id - 1]); | ||
20 | + setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
21 | + setLayout(new MigLayout("insets 3, center")); | ||
22 | + for (int i = 1; i <= 4; i++) { | ||
23 | + JLabel l = new JLabel(); | ||
24 | + l.setOpaque(true); | ||
25 | + l.setBackground(SystemColor.textInactiveText); | ||
26 | + add(l, "w 6!, h 6!"); | ||
27 | + if (i == id) idLabel = l; | ||
28 | + } | ||
29 | + } | ||
30 | + | ||
31 | + public void displayConnected(boolean connected) { | ||
32 | + idLabel.setBackground(connected ? Color.blue : SystemColor.textInactiveText); | ||
33 | + } | ||
34 | + | ||
35 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WiimoteIcon.java~
0 → 100644
@@ -0,0 +1,60 @@ | @@ -0,0 +1,60 @@ | ||
1 | +/* | ||
2 | + * Copyright (C) 2008-2009, Uwe Schmidt | ||
3 | + * | ||
4 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | + * copy of this software and associated documentation files (the "Software"), | ||
6 | + * to deal in the Software without restriction, including without limitation | ||
7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | + * Software is furnished to do so, subject to the following conditions: | ||
10 | + * | ||
11 | + * The above copyright notice and this permission notice shall be included in | ||
12 | + * all copies or substantial portions of the Software. | ||
13 | + * | ||
14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | + * DEALINGS IN THE SOFTWARE. | ||
21 | + * | ||
22 | + * The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
23 | + * the Software and is subject to its own license. | ||
24 | + */ | ||
25 | + | ||
26 | +package org.uweschmidt.wiimote.whiteboard.gui; | ||
27 | + | ||
28 | +import java.awt.Color; | ||
29 | +import java.awt.SystemColor; | ||
30 | + | ||
31 | +import javax.swing.BorderFactory; | ||
32 | +import javax.swing.JLabel; | ||
33 | +import javax.swing.JPanel; | ||
34 | + | ||
35 | +import net.miginfocom.swing.MigLayout; | ||
36 | + | ||
37 | +@SuppressWarnings("serial") | ||
38 | +public class WiimoteIcon extends JPanel { | ||
39 | + | ||
40 | + public static final Color[] COLORS = { Color.white, Color.pink, Color.orange, Color.green }; | ||
41 | + private JLabel idLabel; | ||
42 | + | ||
43 | + public WiimoteIcon(int id) { | ||
44 | + setBackground(COLORS[id - 1]); | ||
45 | + setBorder(BorderFactory.createLineBorder(Color.lightGray)); | ||
46 | + setLayout(new MigLayout("insets 3, center")); | ||
47 | + for (int i = 1; i <= 4; i++) { | ||
48 | + JLabel l = new JLabel(); | ||
49 | + l.setOpaque(true); | ||
50 | + l.setBackground(SystemColor.textInactiveText); | ||
51 | + add(l, "w 6!, h 6!"); | ||
52 | + if (i == id) idLabel = l; | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + public void displayConnected(boolean connected) { | ||
57 | + idLabel.setBackground(connected ? Color.blue : SystemColor.textInactiveText); | ||
58 | + } | ||
59 | + | ||
60 | +} |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_de.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_es.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_et.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_fr.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_in.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_it.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_pl.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_pt.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_ru.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_ru_bak.properties
0 → 100644
@@ -0,0 +1,4 @@ | @@ -0,0 +1,4 @@ | ||
1 | +#Translated by Dmitry Pupinin (dlnsk@mail.ru) | ||
2 | +#Mon Jan 25 00:31:50 NOVT 2010 | ||
3 | +about.Action.text=\u041e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435 | ||
4 | +copyRight=\u0410\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0435 \u043f\u0440\u0430\u0432\u043e \u00a9 %s %s |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_sl.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow.properties
0 → 100644
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +info.Action.text = Calibration Details | ||
2 | +info.Action.shortDescription = Shows details about the current calibration settings. | ||
3 | + | ||
4 | +# no | ||
5 | +trackingUtility.minimum = 0 | ||
6 | +# no | ||
7 | +trackingUtility.maximum = 503316 | ||
8 | +# no | ||
9 | +trackingUtility.stringPainted = true | ||
10 | +# no | ||
11 | +trackingUtility.toolTipText = | ||
12 | + | ||
13 | +# no | ||
14 | +trackingAreaLabel.horizontalAlignment = 0 | ||
15 | +# no | ||
16 | +calibratedScreenLabel.horizontalAlignment = 0 | ||
17 | +# no | ||
18 | +trackingAreaLabel.opaque = true | ||
19 | +# no | ||
20 | +calibratedScreenLabel.opaque = true | ||
21 | + | ||
22 | +trackingAreaLabel.text = Wiimote Tracking Area | ||
23 | +calibratedScreenLabel.text = Calibrated Screen Area | ||
24 | +trackingUtilString = Tracking Utilization: %.0f%% |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_de.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1223760565,Uwe | ||
2 | + | ||
3 | +info.Action.text=Kalibrierungs-Details | ||
4 | + | ||
5 | +info.Action.shortDescription=Zeigt Details \u00fcber die aktuelle Kalibrierung. | ||
6 | + | ||
7 | +trackingAreaLabel.text=Tracking-Bereich der Wiimote | ||
8 | + | ||
9 | +calibratedScreenLabel.text=Kalibrierter Bildschirm-Bereich | ||
10 | + | ||
11 | +trackingUtilString=Tracking-Nutzung: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_es.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1224611921,Descalzo | ||
2 | + | ||
3 | +info.Action.text=Detalles de Calibraci\u00f3n | ||
4 | + | ||
5 | +info.Action.shortDescription=Las detalles de las posici\u00f3nes de la calibraci\u00f3n corriente. | ||
6 | + | ||
7 | +trackingAreaLabel.text=\u00c1rea de Rastreo del Wiimote | ||
8 | + | ||
9 | +calibratedScreenLabel.text=\u00c1rea de la Pantalla Calibrada | ||
10 | + | ||
11 | +trackingUtilString=Utilizaci\u00f3n de Rastreo: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_et.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1248457890,Marko | ||
2 | + | ||
3 | +info.Action.text=Kalibreerimise \u00fcksikasjad | ||
4 | + | ||
5 | +info.Action.shortDescription=N\u00e4itab hetkel kehtiva kalibreeringu \u00fcksikasju. | ||
6 | + | ||
7 | +trackingAreaLabel.text=Wii puldi poolt j\u00e4lgitav ala | ||
8 | + | ||
9 | +calibratedScreenLabel.text=Kalibreeritud ekraani ala | ||
10 | + | ||
11 | +trackingUtilString=J\u00e4lgitava ala h\u00f5ivatus: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_fr.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1223892916,Francois | ||
2 | + | ||
3 | +info.Action.text=D\u00e9tails de la calibration | ||
4 | + | ||
5 | +info.Action.shortDescription=Pr\u00e9sente en d\u00e9tail les param\u00e8tres de la calibration en cours. | ||
6 | + | ||
7 | +trackingAreaLabel.text=Aire suivie par la Wiimote | ||
8 | + | ||
9 | +calibratedScreenLabel.text=Aire d'\u00e9cran calibr\u00e9 | ||
10 | + | ||
11 | +trackingUtilString=Utilisation du suivi: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_in.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1274618605,Bobby | ||
2 | + | ||
3 | +info.Action.text=Detail Kalibrasi | ||
4 | + | ||
5 | +info.Action.shortDescription=Menunjukkan informasi detail mengenai setting Kalibrasi yang digunakan. | ||
6 | + | ||
7 | +trackingAreaLabel.text=Area Tracking Wiimote | ||
8 | + | ||
9 | +calibratedScreenLabel.text=Area layar yang terkalibrasi | ||
10 | + | ||
11 | +trackingUtilString=Penggunaan Tracking: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_it.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1225964626,Francesco | ||
2 | + | ||
3 | +info.Action.text=Dettagli della calibrazione | ||
4 | + | ||
5 | +info.Action.shortDescription=Mostra i dettagli della calibrazione corrente. | ||
6 | + | ||
7 | +trackingAreaLabel.text=Area di tracciamento del Wiimote | ||
8 | + | ||
9 | +calibratedScreenLabel.text=Area di calibrazione schermo | ||
10 | + | ||
11 | +trackingUtilString=Utilizzo del tracciamento: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_pl.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1253207905,Grzegorz | ||
2 | + | ||
3 | +info.Action.text=Szczeg\u00f3\u0142y kalibracji | ||
4 | + | ||
5 | +info.Action.shortDescription=Pokazuje szczeg\u00f3\u0142owe obszary wykonanej kalibracji. | ||
6 | + | ||
7 | +trackingAreaLabel.text=Pole widzenia Wiilot\u00f3w | ||
8 | + | ||
9 | +calibratedScreenLabel.text=Skalibrowane pole ekranu | ||
10 | + | ||
11 | +trackingUtilString=Optymalne wykorzystanie: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_pt.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1223913940,Francisco | ||
2 | + | ||
3 | +info.Action.text=Detalhes da Calibra\u00e7\u00e3o | ||
4 | + | ||
5 | +info.Action.shortDescription=Apresenta os detalhes da presente calibra\u00e7\u00e3o. | ||
6 | + | ||
7 | +trackingAreaLabel.text=\u00c1rea de Visualiza\u00e7\u00e3o do Wiimote | ||
8 | + | ||
9 | +calibratedScreenLabel.text=\u00c1rea de Calibra\u00e7\u00e3o do Ecr\u00e3 | ||
10 | + | ||
11 | +trackingUtilString=Utiliza\u00e7\u00e3o da \u00c1rea de Visualiza\u00e7\u00e3o: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_ru.properties
0 → 100644
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +#Translated by Dmitry Pupinin (dlnsk@mail.ru) | ||
2 | +#Mon Jan 25 00:14:24 NOVT 2010 | ||
3 | +calibratedScreenLabel.text=\u041e\u0442\u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u0430 | ||
4 | +trackingAreaLabel.text=\u041e\u0431\u043b\u0430\u0441\u0442\u044c \u0441\u043b\u0435\u0436\u0435\u043d\u0438\u044f Wiimote | ||
5 | +trackingUtilString=\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c: %.0f%% | ||
6 | +info.Action.text=\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0438 | ||
7 | +info.Action.shortDescription=\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0438. |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_sl.properties
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#:1238601491,Samo | ||
2 | + | ||
3 | +info.Action.text=Podrobnosti kalibracije | ||
4 | + | ||
5 | +info.Action.shortDescription=Prika\u017ee podrobnosti veljavne kalibracije. | ||
6 | + | ||
7 | +trackingAreaLabel.text=Obmo\u010dje zaznavanja | ||
8 | + | ||
9 | +calibratedScreenLabel.text=Kalibrirano obmo\u010dje | ||
10 | + | ||
11 | +trackingUtilString=Izkoristek obmo\u010dja zaznavanja: %.0f%% | ||
12 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_de.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_es.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_et.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_fr.properties
0 → 100644
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +#:1224197209,Francois | ||
2 | + | ||
3 | +# 'Moniteur de la cam\u00e9ra IR' also OK? (need to save some space) | ||
4 | +monitor.Action.text=Moniteur de la cam\u00e9ra IR | ||
5 | + | ||
6 | +monitor.Action.shortDescription=Vous indique ce que les cam\u00e9ras IR des Wiimotes enregistrent. Peut vous aider \u00e0 trouver la meilleure position pour les Wiimotes. | ||
7 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_in.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_it.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_pl.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_pt.properties
0 → 100644
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +#:1224239416,Francisco | ||
2 | + | ||
3 | +# 'Monitoriza\u00e7\u00e3o da C\u00e2mera de IV' also ok? | ||
4 | +monitor.Action.text=Monitoriza\u00e7\u00e3o da C\u00e2mera de IV | ||
5 | + | ||
6 | +monitor.Action.shortDescription=Apresenta o que a c\u00e2mera de infravermelhos do Wiimote v\u00ea. Pode ajudar na escolha duma boa localiza\u00e7\u00e3o para o Wiimote. | ||
7 | + |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_ru.properties
0 → 100644
@@ -0,0 +1,4 @@ | @@ -0,0 +1,4 @@ | ||
1 | +#Translated by Dmitry Pupinin (dlnsk@mail.ru) | ||
2 | +#Mon Jan 25 00:14:24 NOVT 2010 | ||
3 | +monitor.Action.shortDescription=\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e \u0432\u0438\u0434\u0438\u0442 \u0418\u041a-\u043a\u0430\u043c\u0435\u0440\u0430. \u041c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0432\u0430\u043c \u043d\u0430\u0439\u0442\u0438 \u0445\u043e\u0440\u043e\u0448\u0443\u044e \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0434\u043b\u044f Wiimote. | ||
4 | +monitor.Action.text=\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0418\u041a-\u043a\u0430\u043c\u0435\u0440\u044b |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_sl.properties
0 → 100644
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/Credits.html
0 → 100644
@@ -0,0 +1,86 @@ | @@ -0,0 +1,86 @@ | ||
1 | +<html> | ||
2 | +<body> | ||
3 | + | ||
4 | +<div style="text-align: center; font-family: Lucida Grande, Lucida Sans, Verdana; font-size: 11pt;"> | ||
5 | + | ||
6 | +<p> | ||
7 | +<b>Website</b><br> | ||
8 | +<a href="http://www.uweschmidt.org/wiimote-whiteboard">uweschmidt.org/wiimote-whiteboard</a> | ||
9 | +</p> | ||
10 | + | ||
11 | +<p> | ||
12 | +<b>Developer</b><br> | ||
13 | +Uwe Schmidt | ||
14 | +</p> | ||
15 | + | ||
16 | +<p> | ||
17 | +<b>Based on</b><br> | ||
18 | +WiimoteWhiteboard by <a href="http://johnnylee.net/projects/wii/">Johnny Lee</a> | ||
19 | +</p> | ||
20 | + | ||
21 | +<p> | ||
22 | +<b>Translators</b><br> | ||
23 | +<a href="http://estmarx.pri.ee">Marko Puusaar<a> (Estonian)<br> | ||
24 | +<a href="http://perso.univ-lyon2.fr/~fbocquet/">Francois Bocquet<a> (French)<br> | ||
25 | +<a href="http://www.uweschmidt.org">Uwe Schmidt</a> (German)<br> | ||
26 | +<a href="http://bobbyprabowo.wordpress.com">Bobby Adi Prabowo</a> (Indonesian)<br> | ||
27 | +<a href="http://fradelpra.altervista.org">Francesco Del Prato</a>, <a href="http://nilocram.altervista.org/spip/index.php3">Roberto Marcolin</a> (Italian)<br> | ||
28 | +<a href="http://edukom.sytes.net/">Grzegorz Ciaglo</a> (Polish)<br> | ||
29 | +<a href="http://clinik.net/wiimote/">Francisco Cardoso Lima</a> (Portuguese)<br> | ||
30 | +Dmitry Pupinin (Russian)<br> | ||
31 | +Samo Vesel (Slovene)<br> | ||
32 | +Peter Skouson (Spanish)<br> | ||
33 | +</p> | ||
34 | + | ||
35 | +<p> | ||
36 | +<b>Third Party Software</b><br> | ||
37 | +<a href="http://www.centerkey.com/java/browser/">Bare Bones Browser Launch<a><br> | ||
38 | +<a href="http://www.bluecove.org/">BlueCove</a><br> | ||
39 | +<a href="https://jai-core.dev.java.net/">Java Advanced Imaging</a><br> | ||
40 | +<a href="http://www.miglayout.com/">MiGLayout</a><br> | ||
41 | +<a href="http://www.sciss.de/netutil/">NetUtil</a><br> | ||
42 | +<a href="http://developer.apple.com/samplecode/OSXAdapter/listing3.html">OSXAdapter</a><br> | ||
43 | +<a href="https://appframework.dev.java.net/">Swing Application Framework</a><br> | ||
44 | +<a href="https://swingworker.dev.java.net/">Swing Worker</a><br> | ||
45 | +<a href="http://www.world-of-cha0s.hostrocket.com/WiiRemoteJ/">WiiRemoteJ</a><br> | ||
46 | +</p> | ||
47 | + | ||
48 | +<p> | ||
49 | +<b>Icons</b><br> | ||
50 | +<a href="http://www.everaldo.com/crystal/">Crystal Project<a><br> | ||
51 | +<a href="http://clinik.net/wiimote/">Francisco Cardoso Lima</a> - Application Icon, Calibration Icons | ||
52 | +</p> | ||
53 | + | ||
54 | +<p> | ||
55 | +<b>Warranty Information</b><br> | ||
56 | +This software is licensed<br> | ||
57 | +under a modified MIT License: | ||
58 | +</p> | ||
59 | + | ||
60 | +<div style="color: gray; padding: 5px; text-align: justify;"> | ||
61 | +Permission is hereby granted, free of charge, to any person obtaining a | ||
62 | +copy of this software and associated documentation files (the "Software"), | ||
63 | +to deal in the Software without restriction, including without limitation | ||
64 | +the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
65 | +and/or sell copies of the Software, and to permit persons to whom the | ||
66 | +Software is furnished to do so, subject to the following conditions: <br><br> | ||
67 | + | ||
68 | +The above copyright notice and this permission notice shall be included in | ||
69 | +all copies or substantial portions of the Software. <br><br> | ||
70 | + | ||
71 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
72 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
73 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
74 | +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
75 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
76 | +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
77 | +DEALINGS IN THE SOFTWARE. <br><br> | ||
78 | + | ||
79 | +The Software uses a third-party library (WiiRemoteJ) which is not part of | ||
80 | +the Software and is subject to its own license. | ||
81 | +</div> | ||
82 | +</div> | ||
83 | + | ||
84 | + | ||
85 | +</body> | ||
86 | +</html> | ||
0 | \ No newline at end of file | 87 | \ No newline at end of file |
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/HelpHandler.properties
0 → 100644