@@ -45,18 +45,27 @@ class W_EMGJoystick extends Widget {
4545 private float leftPolarX, leftPolarY; // 9:00
4646 private final int EMG_PLOT_OFFSET = 40 ; // Used to arrange EMG displays outside of X/Y graph
4747
48- private final String CHANNEL_ONE_LABEL_EN = " Channel 1" ;
49- private final String CHANNEL_TWO_LABEL_EN = " Channel 2" ;
50- private final String CHANNEL_THREE_LABEL_EN = " Channel 3" ;
51- private final String CHANNEL_FOUR_LABEL_EN = " Channel 4" ;
52-
53- private String channelOneLabel;
54- private String channelTwoLabel;
55- private String channelThreeLabel;
56- private String channelFourLabel;
48+ private String [] plotChannelLabels = new String [NUM_EMG_CHANNELS ];
5749
5850 EmgJoystickSmoothing joystickSmoothing = EmgJoystickSmoothing . POINT_9 ;
5951
52+ private int DROPDOWN_HEIGHT = navH - 4 ;
53+ private int DROPDOWN_WIDTH = 80 ;
54+ private int DROPDOWN_SPACER = 10 ;
55+ private int DROPDOWN_LABEL_WIDTH = 24 ;
56+
57+ EmgJoystickInput [] emgJoystickInputs = new EmgJoystickInput [NUM_EMG_CHANNELS ];
58+
59+ ScrollableList xNegativeInputDropdown;
60+ ScrollableList xPositiveInputDropdown;
61+ ScrollableList yPositiveInputDropdown;
62+ ScrollableList yNegativeInputDropdown;
63+
64+ TextBox xNegativeInputDropdownLabel;
65+ TextBox xPositiveInputDropdownLabel;
66+ TextBox yPositiveInputDropdownLabel;
67+ TextBox yNegativeInputDropdownLabel;
68+
6069 W_EMGJoystick (PApplet _parent ){
6170 super (_parent); // calls the parent CONSTRUCTOR method of Widget (DON'T REMOVE)
6271
@@ -71,13 +80,18 @@ class W_EMGJoystick extends Widget {
7180
7281 emgSettingsValues = dataProcessing. emgSettings. values;
7382
74- channelOneLabel = CHANNEL_ONE_LABEL_EN ;
75- channelTwoLabel = CHANNEL_TWO_LABEL_EN ;
76- channelThreeLabel = CHANNEL_THREE_LABEL_EN ;
77- channelFourLabel = CHANNEL_FOUR_LABEL_EN ;
83+ emgJoystickInputs[0 ] = EmgJoystickInput . CHANNEL_1 ;
84+ emgJoystickInputs[1 ] = EmgJoystickInput . CHANNEL_2 ;
85+ emgJoystickInputs[2 ] = EmgJoystickInput . CHANNEL_3 ;
86+ emgJoystickInputs[3 ] = EmgJoystickInput . CHANNEL_4 ;
87+
88+ for (int i = 0 ; i < NUM_EMG_CHANNELS ; i++ ) {
89+ plotChannelLabels[i] = Integer . toString(emgJoystickInputs[i]. getIndex() + 1 );
90+ }
7891
7992 addDropdown(" emgJoystickSmoothingDropdown" , " Smoothing" , joystickSmoothing. getEnumStringsAsList(), joystickSmoothing. getIndex());
8093
94+ createInputDropdowns();
8195 }
8296
8397 public void update (){
@@ -91,12 +105,14 @@ class W_EMGJoystick extends Widget {
91105
92106 drawJoystickXYGraph();
93107
94- drawEmgVisualization(0 , leftPolarX, leftPolarY);
95- drawEmgVisualization(1 , rightPolarX, rightPolarY);
96- drawEmgVisualization(2 , topPolarX, topPolarY);
97- drawEmgVisualization(3 , bottomPolarX, bottomPolarY);
108+ drawEmgVisualization(emgJoystickInputs[ 0 ] . getIndex() , leftPolarX, leftPolarY);
109+ drawEmgVisualization(emgJoystickInputs[ 1 ] . getIndex() , rightPolarX, rightPolarY);
110+ drawEmgVisualization(emgJoystickInputs[ 2 ] . getIndex() , topPolarX, topPolarY);
111+ drawEmgVisualization(emgJoystickInputs[ 3 ] . getIndex() , bottomPolarX, bottomPolarY);
98112
99- drawChannelLabels();
113+ // drawChannelLabels();
114+
115+ drawInputDropdownLabels();
100116
101117 emgCp5. draw();
102118 }
@@ -108,6 +124,7 @@ class W_EMGJoystick extends Widget {
108124 emgSettingsButton. setPosition(x0 + 1 , y0 + navH + 1 );
109125
110126 updateJoystickGraphSizeAndPosition();
127+ updateInputDropdownPositions();
111128 }
112129
113130 private void updateJoystickGraphSizeAndPosition () {
@@ -183,7 +200,8 @@ class W_EMGJoystick extends Widget {
183200
184201 popStyle ();
185202 }
186-
203+
204+ // This is the core method that updates the joystick input
187205 private void updateJoystickInput () {
188206 previousJoystickRawX = joystickRawX;
189207 previousJoystickRawY = joystickRawY;
@@ -193,11 +211,16 @@ class W_EMGJoystick extends Widget {
193211 joystickRawY = 0 ;
194212 return ;
195213 }
214+
215+ float xNegativeValue = emgSettingsValues. outputNormalized[emgJoystickInputs[0 ]. getIndex()];
216+ float xPositiveValue = emgSettingsValues. outputNormalized[emgJoystickInputs[1 ]. getIndex()];
217+ float yPositiveValue = emgSettingsValues. outputNormalized[emgJoystickInputs[2 ]. getIndex()];
218+ float yNegativeValue = emgSettingsValues. outputNormalized[emgJoystickInputs[3 ]. getIndex()];
196219
197- // Here we subtract the values of the left and right channels to get the X axis
198- joystickRawX = emgSettingsValues . outputNormalized[ 1 ] - emgSettingsValues . outputNormalized[ 0 ] ;
199- // Here we subtract the values of the top and bottom channels to get the Y axis
200- joystickRawY = emgSettingsValues . outputNormalized[ 2 ] - emgSettingsValues . outputNormalized[ 3 ] ;
220+ // Here we subtract the value of the right channel from the left channel to get the X axis
221+ joystickRawX = xPositiveValue - xNegativeValue ;
222+ // Here we subtract the value of the top channel from the bottom channel to get the Y axis
223+ joystickRawY = yPositiveValue - yNegativeValue ;
201224
202225 // Map the joystick values to a unit circle
203226 float [] unitCircleXY = mapToUnitCircle(joystickRawX, joystickRawY);
@@ -266,17 +289,6 @@ class W_EMGJoystick extends Widget {
266289 noFill ();
267290 rect (barX, barY, BAR_WIDTH , BAR_HEIGHT * - 1 );
268291
269- /*
270- //draw channel number at upper left corner of row/column cell
271- pushStyle();
272- stroke(OPENBCI_DARKBLUE);
273- fill(OPENBCI_DARKBLUE);
274- int _chan = index+1;
275- textFont(p5, 12);
276- text(_chan + "", 10, 20);
277- popStyle();
278- */
279-
280292 popStyle ();
281293 }
282294
@@ -287,11 +299,11 @@ class W_EMGJoystick extends Widget {
287299 textFont (p4, 14 );
288300 textLeading (14 );
289301 textAlign (CENTER ,CENTER );
290-
291- text (channelOneLabel , leftPolarX, leftPolarY - BAR_CIRCLE_SPACER * 2 );
292- text (channelTwoLabel , rightPolarX, rightPolarY - BAR_CIRCLE_SPACER * 2 );
293- text (channelThreeLabel , topPolarX + BAR_CIRCLE_SPACER * 4 , topPolarY);
294- text (channelFourLabel , bottomPolarX + BAR_CIRCLE_SPACER * 4 , bottomPolarY);
302+
303+ text (plotChannelLabels[ 0 ] , leftPolarX, leftPolarY - BAR_CIRCLE_SPACER * 2 );
304+ text (plotChannelLabels[ 1 ] , rightPolarX, rightPolarY - BAR_CIRCLE_SPACER * 2 );
305+ text (plotChannelLabels[ 2 ] , topPolarX + BAR_CIRCLE_SPACER * 4 , topPolarY);
306+ text (plotChannelLabels[ 3 ] , bottomPolarX + BAR_CIRCLE_SPACER * 4 , bottomPolarY);
295307
296308 popStyle ();
297309 }
@@ -314,6 +326,104 @@ class W_EMGJoystick extends Widget {
314326 emgSettingsButton. setDescription(" Click to open the EMG Settings UI to adjust how this metric is calculated." );
315327 }
316328
329+ private ScrollableList createEmgJoystickInputDropdown (String name , EmgJoystickInput joystickInput , int inputNumber ) {
330+ ScrollableList list = emgCp5. addScrollableList(name)
331+ .setOpen(false )
332+ .setColorBackground(WHITE ) // text field bg color
333+ .setColorValueLabel(OPENBCI_DARKBLUE ) // text color
334+ .setColorCaptionLabel(OPENBCI_DARKBLUE )
335+ .setColorForeground(color (125 )) // border color when not selected
336+ .setColorActive(BUTTON_PRESSED ) // border color when selected
337+ .setOutlineColor(OBJECT_BORDER_GREY )
338+ .setSize(DROPDOWN_WIDTH , DROPDOWN_HEIGHT * 6 )// temporary size
339+ .setBarHeight(DROPDOWN_HEIGHT ) // height of top/primary bar
340+ .setItemHeight(DROPDOWN_HEIGHT ) // height of all item/dropdown bars
341+ .setVisible(true )
342+ ;
343+ // this will store the *actual* enum object inside the dropdown!
344+ for (EmgJoystickInput input : EmgJoystickInput . values()) {
345+ if (input. getIndex() >= currentBoard. getNumEXGChannels()) {
346+ continue ;
347+ }
348+ list. addItem(input. getString(), input);
349+ }
350+ // Style the text in the ScrollableList
351+ list. getCaptionLabel() // the caption label is the text object in the primary bar
352+ .toUpperCase(false ) // DO NOT AUTOSET TO UPPERCASE!!!
353+ .setText(joystickInput. getString())
354+ .setFont(h5)
355+ .setSize(12 )
356+ .getStyle() // need to grab style before affecting the paddingTop
357+ .setPaddingTop(4 )
358+ ;
359+ list. getValueLabel() // the value label is connected to the text objects in the dropdown item bars
360+ .toUpperCase(false ) // DO NOT AUTOSET TO UPPERCASE!!!
361+ .setText(joystickInput. getString())
362+ .setFont(p6)
363+ .setSize(10 ) // set the font size of the item bars to 14pt
364+ .getStyle() // need to grab style before affecting the paddingTop
365+ .setPaddingTop(3 ) // 4-pixel vertical offset to center text
366+ ;
367+ list. addCallback(new SLCallbackListener (inputNumber));
368+ return list;
369+ }
370+
371+ private class SLCallbackListener implements CallbackListener {
372+ private int inputNumber;
373+
374+ SLCallbackListener (int _i ) {
375+ inputNumber = _i;
376+ }
377+ public void controlEvent (CallbackEvent theEvent ) {
378+ // Selecting an item from ScrollableList triggers Broadcast
379+ if (theEvent. getAction() == ControlP5 . ACTION_BROADCAST ) {
380+ int val = (int )(theEvent. getController()). getValue();
381+ Map bob = ((ScrollableList )theEvent. getController()). getItem(val);
382+ emgJoystickInputs[inputNumber] = (EmgJoystickInput )bob. get(" value" );
383+ verbosePrint(" EmgJoystickInput: " + (theEvent. getController()). getName() + " == " + emgJoystickInputs[inputNumber]. getString());
384+
385+ plotChannelLabels[inputNumber] = Integer . toString(emgJoystickInputs[inputNumber]. getIndex() + 1 );
386+ }
387+ }
388+ }
389+
390+ private void createInputDropdowns () {
391+ // Create the dropdowns in reverse order so that top dropdown draws over bottom dropdown
392+ yNegativeInputDropdown = createEmgJoystickInputDropdown(" yNegativeDropdown" , emgJoystickInputs[3 ], 3 );
393+ yPositiveInputDropdown = createEmgJoystickInputDropdown(" yPositiveDropdown" , emgJoystickInputs[2 ], 2 );
394+ xPositiveInputDropdown = createEmgJoystickInputDropdown(" xPositiveDropdown" , emgJoystickInputs[1 ], 1 );
395+ xNegativeInputDropdown = createEmgJoystickInputDropdown(" xNegativeDropdown" , emgJoystickInputs[0 ], 0 );
396+ // Add the dropdowns to the list of cp5 elements to check for mouseover
397+ cp5ElementsToCheck. add(xNegativeInputDropdown);
398+ cp5ElementsToCheck. add(xPositiveInputDropdown);
399+ cp5ElementsToCheck. add(yPositiveInputDropdown);
400+ cp5ElementsToCheck. add(yNegativeInputDropdown);
401+ // Create labels for the dropdowns
402+ color labelBG = color (255 ,255 ,255 ,0 );
403+ xNegativeInputDropdownLabel = new TextBox (" X-" , x, y, OPENBCI_DARKBLUE , WHITE , 12 , h3, LEFT , TOP );
404+ xPositiveInputDropdownLabel = new TextBox (" X+" , x, y, OPENBCI_DARKBLUE , WHITE , 12 , h3, LEFT , TOP );
405+ yPositiveInputDropdownLabel = new TextBox (" Y+" , x, y, OPENBCI_DARKBLUE , WHITE , 12 , h3, LEFT , TOP );
406+ yNegativeInputDropdownLabel = new TextBox (" Y-" , x, y, OPENBCI_DARKBLUE , WHITE , 12 , h3, LEFT , TOP );
407+ }
408+
409+ private void updateInputDropdownPositions (){
410+ xNegativeInputDropdown. setPosition((int ) (x + navH + DROPDOWN_LABEL_WIDTH ), (int ) (y + navH + 1 ));
411+ xPositiveInputDropdown. setPosition((int ) (x + navH + DROPDOWN_LABEL_WIDTH ), (int ) (y + navH + DROPDOWN_SPACER + DROPDOWN_HEIGHT ));
412+ yPositiveInputDropdown. setPosition((int ) (x + w - navH - DROPDOWN_WIDTH ), (int ) (y + navH + 1 ));
413+ yNegativeInputDropdown. setPosition((int ) (x + w - navH - DROPDOWN_WIDTH ), (int ) (y + navH + DROPDOWN_SPACER + DROPDOWN_HEIGHT ));
414+ xNegativeInputDropdownLabel. setPosition((int ) xNegativeInputDropdown. getPosition()[0 ] - DROPDOWN_LABEL_WIDTH , (int ) xNegativeInputDropdown. getPosition()[1 ]);
415+ xPositiveInputDropdownLabel. setPosition((int ) xPositiveInputDropdown. getPosition()[0 ] - DROPDOWN_LABEL_WIDTH , (int ) xPositiveInputDropdown. getPosition()[1 ]);
416+ yPositiveInputDropdownLabel. setPosition((int ) yPositiveInputDropdown. getPosition()[0 ] - DROPDOWN_LABEL_WIDTH , (int ) yPositiveInputDropdown. getPosition()[1 ]);
417+ yNegativeInputDropdownLabel. setPosition((int ) yNegativeInputDropdown. getPosition()[0 ] - DROPDOWN_LABEL_WIDTH , (int ) yNegativeInputDropdown. getPosition()[1 ]);
418+ }
419+
420+ private void drawInputDropdownLabels () {
421+ xNegativeInputDropdownLabel. draw();
422+ xPositiveInputDropdownLabel. draw();
423+ yPositiveInputDropdownLabel. draw();
424+ yNegativeInputDropdownLabel. draw();
425+ }
426+
317427};
318428
319429public void emgJoystickSmoothingDropdown (int n ) {
@@ -353,6 +463,57 @@ public enum EmgJoystickSmoothing implements IndexingInterface
353463 return value;
354464 }
355465
466+ private static List<String > getEnumStringsAsList () {
467+ List<String > enumStrings = new ArrayList<String > ();
468+ for (IndexingInterface val : vals) {
469+ enumStrings. add(val. getString());
470+ }
471+ return enumStrings;
472+ }
473+ }
474+
475+ public enum EmgJoystickInput implements IndexingInterface
476+ {
477+ CHANNEL_1 (0 , " Channel 1" , 0 ),
478+ CHANNEL_2 (1 , " Channel 2" , 1 ),
479+ CHANNEL_3 (2 , " Channel 3" , 2 ),
480+ CHANNEL_4 (3 , " Channel 4" , 3 ),
481+ CHANNEL_5 (4 , " Channel 5" , 4 ),
482+ CHANNEL_6 (5 , " Channel 6" , 5 ),
483+ CHANNEL_7 (6 , " Channel 7" , 6 ),
484+ CHANNEL_8 (7 , " Channel 8" , 7 ),
485+ CHANNEL_9 (8 , " Channel 9" , 8 ),
486+ CHANNEL_10 (9 , " Channel 10" , 9 ),
487+ CHANNEL_11 (10 , " Channel 11" , 10 ),
488+ CHANNEL_12 (11 , " Channel 12" , 11 ),
489+ CHANNEL_13 (12 , " Channel 13" , 12 ),
490+ CHANNEL_14 (13 , " Channel 14" , 13 ),
491+ CHANNEL_15 (14 , " Channel 15" , 14 ),
492+ CHANNEL_16 (15 , " Channel 16" , 15 );
493+
494+ private int index;
495+ private String name;
496+ private int value;
497+ private static EmgJoystickInput [] vals = values();
498+
499+ EmgJoystickInput (int index , String name , int value ) {
500+ this . index = index;
501+ this . name = name;
502+ this . value = value;
503+ }
504+
505+ public int getIndex () {
506+ return index;
507+ }
508+
509+ public String getString () {
510+ return name;
511+ }
512+
513+ public int getValue () {
514+ return value;
515+ }
516+
356517 private static List<String > getEnumStringsAsList () {
357518 List<String > enumStrings = new ArrayList<String > ();
358519 for (IndexingInterface val : vals) {
0 commit comments