/
panel_ieeg.m
2682 lines (2562 loc) · 117 KB
/
panel_ieeg.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
function varargout = panel_ieeg(varargin)
% PANEL_IEEG: Create a panel to edit SEEG/ECOG contact positions.
%
% USAGE: bstPanelNew = panel_ieeg('CreatePanel')
% panel_ieeg('UpdatePanel')
% panel_ieeg('UpdateElecList')
% panel_ieeg('UpdateElecProperties')
% panel_ieeg('CurrentFigureChanged_Callback')
% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2017-2022
eval(macro_method);
end
%% ===== CREATE PANEL =====
function bstPanelNew = CreatePanel() %#ok<DEFNU>
panelName = 'iEEG';
% Java initializations
import java.awt.*;
import javax.swing.*;
import org.brainstorm.icon.*;
% Create tools panel
jPanelNew = gui_component('Panel');
jPanelTop = gui_component('Panel');
jPanelNew.add(jPanelTop, BorderLayout.NORTH);
TB_DIM = java_scaled('dimension',25,25);
% ===== TOOLBAR =====
jMenuBar = gui_component('MenuBar', jPanelTop, BorderLayout.NORTH);
jToolbar = gui_component('Toolbar', jMenuBar);
jToolbar.setPreferredSize(TB_DIM);
jToolbar.setOpaque(0);
% Add/remove
gui_component('ToolbarButton', jToolbar,[],[], {IconLoader.ICON_PLUS, TB_DIM}, 'Add new electrode', @(h,ev)bst_call(@AddElectrode));
gui_component('ToolbarButton', jToolbar,[],[], {IconLoader.ICON_MINUS, TB_DIM}, 'Remove selected electrodes', @(h,ev)bst_call(@RemoveElectrode));
% Set color
jToolbar.addSeparator();
gui_component('ToolbarButton', jToolbar,[],[], {IconLoader.ICON_COLOR_SELECTION, TB_DIM}, 'Select color for selected electrodes', @(h,ev)bst_call(@EditElectrodeColor));
% Show/Hide
jButtonShow = gui_component('ToolbarToggle', jToolbar, [], [], {IconLoader.ICON_DISPLAY, TB_DIM}, 'Show/hide selected electrodes', @(h,ev)bst_call(@SetElectrodeVisible, ev.getSource().isSelected()));
jButtonShow.setSelected(1);
% Set display mode
jToolbar.addSeparator();
jButtonGroup = ButtonGroup();
jRadioDispDepth = gui_component('ToolbarToggle', jToolbar, [], [], {IconLoader.ICON_SEEG_DEPTH, jButtonGroup, TB_DIM}, 'Display contacts as SEEG electrodes/ECOG strips', @(h,ev)bst_call(@SetDisplayMode, 'depth'));
jRadioDispSphere = gui_component('ToolbarToggle', jToolbar, [], [], {IconLoader.ICON_SEEG_SPHERE, jButtonGroup, TB_DIM}, 'Display contacts as spheres', @(h,ev)bst_call(@SetDisplayMode, 'sphere'));
% Menu: Contacts
jToolbar.addSeparator();
jMenuContacts = gui_component('ToolbarButton', jToolbar, [], 'Contacts', IconLoader.ICON_MENU, '', @(h,ev)ShowContactsMenu(ev.getSource()), []);
% ===== PANEL MAIN =====
jPanelMain = gui_component('Panel');
jPanelMain.setBorder(BorderFactory.createEmptyBorder(7,7,7,7));
% % ===== VERTICAL TOOLBAR =====
% jToolbar2 = gui_component('Toolbar', jPanelMain, BorderLayout.EAST);
% jToolbar2.setOrientation(jToolbar.VERTICAL);
% jToolbar2.setPreferredSize(java_scaled('dimension',26,20));
% jToolbar2.setBorder([]);
% ===== FIRST PART =====
jPanelFirstPart = gui_component('Panel');
% ===== ELECTRODES LIST =====
jPanelElecList = gui_component('Panel');
jBorder = java_scaled('titledborder', 'Electrodes');
jPanelElecList.setBorder(jBorder);
% Electrodes list
jListElec = java_create('org.brainstorm.list.BstClusterList');
jListElec.setBackground(Color(.9,.9,.9));
jListElec.setLayoutOrientation(jListElec.VERTICAL_WRAP);
jListElec.setVisibleRowCount(-1);
java_setcb(jListElec, ...
'ValueChangedCallback', @(h,ev)bst_call(@ElecListValueChanged_Callback,h,ev), ...
'KeyTypedCallback', @(h,ev)bst_call(@ElecListKeyTyped_Callback,h,ev), ...
'MouseClickedCallback', @(h,ev)bst_call(@ElecListClick_Callback,h,ev));
jPanelScrollList = JScrollPane();
jPanelScrollList.getLayout.getViewport.setView(jListElec);
jPanelScrollList.setBorder([]);
jPanelElecList.add(jPanelScrollList);
jPanelFirstPart.add(jPanelElecList, BorderLayout.CENTER);
jPanelMain.add(jPanelFirstPart);
jPanelBottom = gui_river([0,0], [0,0,0,0]);
% ===== ELECTRODE OPTIONS =====
jPanelElecOptions = gui_river([0,3], [0,5,10,3], 'Electrode configuration');
% Electrode type
gui_component('label', jPanelElecOptions, '', 'Type: ');
jButtonGroup = ButtonGroup();
jRadioSeeg = gui_component('radio', jPanelElecOptions, '', 'SEEG', jButtonGroup, '', @(h,ev)ValidateOptions('Type', ev.getSource()));
jRadioEcog = gui_component('radio', jPanelElecOptions, '', 'ECOG', jButtonGroup, '', @(h,ev)ValidateOptions('Type', ev.getSource()));
jRadioEcogMid = gui_component('radio', jPanelElecOptions, '', 'ECOG-mid', jButtonGroup, '', @(h,ev)ValidateOptions('Type', ev.getSource()));
jRadioSeeg.setMargin(java.awt.Insets(0,0,0,0));
jRadioEcog.setMargin(java.awt.Insets(0,0,0,0));
jRadioEcogMid.setMargin(java.awt.Insets(0,0,0,0));
% Electrode model
jPanelModel = gui_river([0,0], [0,0,0,0]);
% Title
gui_component('label', jPanelModel, '', 'Model: ');
% Combo box
jComboModel = gui_component('combobox', jPanelModel, 'hfill', [], [], [], []);
jComboModel.setFocusable(0);
jComboModel.setMaximumRowCount(15);
jComboModel.setPreferredSize(java_scaled('dimension',30,20));
% ComboBox change selection callback
jModel = jComboModel.getModel();
java_setcb(jModel, 'ContentsChangedCallback', @(h,ev)bst_call(@ComboModelChanged_Callback,h,ev));
% Add/remove models
gui_component('button', jPanelModel,'right',[], {IconLoader.ICON_PLUS, java_scaled('dimension',22,22)}, 'Add new electrode model', @(h,ev)bst_call(@AddElectrodeModel));
gui_component('button', jPanelModel,[],[], {IconLoader.ICON_MINUS, java_scaled('dimension',22,22)}, 'Remove electrode model', @(h,ev)bst_call(@RemoveElectrodeModel));
jPanelElecOptions.add('br hfill', jPanelModel);
% Number of contacts
gui_component('label', jPanelElecOptions, 'br', 'Number of contacts: ');
jTextNcontacts = gui_component('text', jPanelElecOptions, 'tab', '');
jTextNcontacts.setHorizontalAlignment(jTextNcontacts.RIGHT);
% Contacts spacing
gui_component('label', jPanelElecOptions, 'br', 'Contact spacing: ');
jTextSpacing = gui_component('text', jPanelElecOptions, 'tab', '');
jTextSpacing.setHorizontalAlignment(jTextNcontacts.RIGHT);
gui_component('label', jPanelElecOptions, '', ' mm');
% Contacts length
jLabelContactLength = gui_component('label', jPanelElecOptions, 'br', 'Contact length: ');
jTextContactLength = gui_component('texttime', jPanelElecOptions, 'tab', '');
gui_component('label', jPanelElecOptions, '', ' mm');
% Contacts diameter
gui_component('label', jPanelElecOptions, 'br', 'Contact diameter: ');
jTextContactDiam = gui_component('texttime', jPanelElecOptions, 'tab', '');
gui_component('label', jPanelElecOptions, '', ' mm');
% Electrode diameter
jLabelElecDiameter = gui_component('label', jPanelElecOptions, 'br', 'Electrode diameter: ');
jTextElecDiameter = gui_component('texttime', jPanelElecOptions, 'tab', '');
jLabelElecDiamUnits = gui_component('label', jPanelElecOptions, '', ' mm');
% Electrode length
jLabelElecLength = gui_component('label', jPanelElecOptions, 'br', 'Electrode length: ');
jTextElecLength = gui_component('texttime', jPanelElecOptions, 'tab', '');
jLabelElecLengthUnits = gui_component('label', jPanelElecOptions, '', ' mm');
% Set electrode position
jPanelButtons = gui_component('panel');
jCardLayout = java.awt.CardLayout;
jPanelButtons.setLayout(jCardLayout);
jPanelButtons.add(gui_component('panel'), 'none');
jPanelButtonsSeeg = gui_river([0,0], [0,0,0,0]);
jButtonSeegSet1 = gui_component('button', jPanelButtonsSeeg, 'center', 'Set tip', [], '<HTML>Set electrode tip: contact #1<BR>(MRI Viewer must be open)', @(h,ev)bst_call(@SetElectrodeLoc, 1, ev.getSource()));
jButtonSeegSet2 = gui_component('button', jPanelButtonsSeeg, 'center', 'Set skull entry', [], '<HTML>Set entry point in the skull (does not match the position of a contact)<BR>(MRI Viewer must be open)', @(h,ev)bst_call(@SetElectrodeLoc, 2, ev.getSource()));
jPanelButtons.add(jPanelButtonsSeeg, 'seeg');
jPanelButtonsEcog = gui_river([0,0], [0,0,0,0]);
jButtonEcogSet1 = gui_component('button', jPanelButtonsEcog, 'center', '#1', [], '<HTML>Set contact #1 of the ECOG grid/strip<BR>(MRI Viewer must be open)', @(h,ev)bst_call(@SetElectrodeLoc, 1, ev.getSource()));
jButtonEcogSet2 = gui_component('button', jPanelButtonsEcog, 'center', '#2', [], '<HTML>ECOG strip: Set the last contact of the strip.<BR>ECOG grid: Set the second corner in the list of contacts.<BR>(MRI Viewer must be open)', @(h,ev)bst_call(@SetElectrodeLoc, 2, ev.getSource()));
jButtonEcogSet3 = gui_component('button', jPanelButtonsEcog, 'center', '#3', [], '<HTML>ECOG strip: N/A.<BR>ECOG grid: Set third corner of the grid (last contact, opposite to contact #1).<BR>(MRI Viewer must be open)', @(h,ev)bst_call(@SetElectrodeLoc, 3, ev.getSource()));
jButtonEcogSet4 = gui_component('button', jPanelButtonsEcog, 'center', '#4', [], '<HTML>ECOG strip: N/A.<BR>ECOG grid: Set third corner of the grid (opposite to contact #2).<BR>(MRI Viewer must be open)', @(h,ev)bst_call(@SetElectrodeLoc, 4, ev.getSource()));
jPanelButtons.add(jPanelButtonsEcog, 'ecog');
jCardLayout.show(jPanelButtons, 'seeg');
jPanelElecOptions.add('br hfill', jPanelButtons);
jPanelBottom.add('hfill', jPanelElecOptions);
jPanelMain.add(jPanelBottom, BorderLayout.SOUTH)
jPanelNew.add(jPanelMain, BorderLayout.CENTER);
% Store electrode selection
jLabelSelectElec = JLabel('');
% Create the BstPanel object that is returned by the function
bstPanelNew = BstPanel(panelName, ...
jPanelNew, ...
struct('jPanelMain', jPanelMain, ...
'jPanelElecList', jPanelElecList, ...
'jToolbar', jToolbar, ...
'jPanelElecOptions', jPanelElecOptions, ...
'jButtonShow', jButtonShow, ...
'jRadioDispDepth', jRadioDispDepth, ...
'jRadioDispSphere', jRadioDispSphere, ...
'jMenuContacts', jMenuContacts, ...
'jListElec', jListElec, ...
'jComboModel', jComboModel, ...
'jRadioSeeg', jRadioSeeg, ...
'jRadioEcog', jRadioEcog, ...
'jRadioEcogMid', jRadioEcogMid, ...
'jTextNcontacts', jTextNcontacts, ...
'jTextSpacing', jTextSpacing, ...
'jTextContactDiam', jTextContactDiam, ...
'jLabelContactLength', jLabelContactLength, ...
'jTextContactLength', jTextContactLength, ...
'jLabelElecLength', jLabelElecLength, ...
'jTextElecLength', jTextElecLength, ...
'jLabelElecLengthUnits',jLabelElecLengthUnits, ...
'jLabelElecDiameter', jLabelElecDiameter, ...
'jTextElecDiameter', jTextElecDiameter, ...
'jLabelElecDiamUnits', jLabelElecDiamUnits, ...
'jLabelSelectElec', jLabelSelectElec, ...
'jPanelButtonsSeeg', jPanelButtonsSeeg, ...
'jPanelButtonsEcog', jPanelButtonsEcog, ...
'jPanelButtons', jPanelButtons, ...
'jCardLayout', jCardLayout, ...
'jButtonSeegSet1', jButtonSeegSet1, ...
'jButtonSeegSet2', jButtonSeegSet2, ...
'jButtonEcogSet1', jButtonEcogSet1, ...
'jButtonEcogSet2', jButtonEcogSet2, ...
'jButtonEcogSet3', jButtonEcogSet3, ...
'jButtonEcogSet4', jButtonEcogSet4));
%% =================================================================================
% === INTERNAL CALLBACKS =========================================================
% =================================================================================
%% ===== MODEL SELECTION =====
function ComboModelChanged_Callback(varargin)
% Get selected model
[iModel, sModels] = GetSelectedModel();
% Get the selected electrode
[sSelElec, iSelElec] = GetSelectedElectrodes();
% Reset Model field
if isempty(iModel)
[sSelElec.Model] = deal([]);
% Copy model values to electrodes
else
for i = 1:length(sSelElec)
sSelElec(i).Model = sModels(iModel).Model;
if ~isempty(sModels(iModel).ContactNumber)
sSelElec(i).ContactNumber = sModels(iModel).ContactNumber;
end
if ~isempty(sModels(iModel).ContactSpacing)
sSelElec(i).ContactSpacing = sModels(iModel).ContactSpacing;
end
if ~isempty(sModels(iModel).ContactDiameter)
sSelElec(i).ContactDiameter = sModels(iModel).ContactDiameter;
end
if ~isempty(sModels(iModel).ContactLength)
sSelElec(i).ContactLength = sModels(iModel).ContactLength;
end
if ~isempty(sModels(iModel).ElecDiameter)
sSelElec(i).ElecDiameter = sModels(iModel).ElecDiameter;
end
if ~isempty(sModels(iModel).ContactNumber)
sSelElec(i).ElecLength = sModels(iModel).ElecLength;
end
end
end
% Update electrode properties
SetElectrodes(iSelElec, sSelElec);
% Update display
UpdateElecProperties(0);
% Update figures
UpdateFigures();
end
%% ===== LIST SELECTION CHANGED CALLBACK =====
function ElecListValueChanged_Callback(h, ev)
if ~ev.getValueIsAdjusting()
UpdateElecProperties();
% Get the selected electrode
[sSelElec, iSelElec] = GetSelectedElectrodes();
% Center MRI view on electrode tip
if (length(sSelElec) == 1)
CenterMriOnElectrode(sSelElec);
end
end
end
%% ===== LIST KEY TYPED CALLBACK =====
function ElecListKeyTyped_Callback(h, ev)
switch(uint8(ev.getKeyChar()))
% DELETE
case {ev.VK_DELETE, ev.VK_BACK_SPACE}
RemoveElectrode();
case ev.VK_ESCAPE
SetSelectedElectrodes(0);
end
end
%% ===== LIST CLICK CALLBACK =====
function ElecListClick_Callback(h, ev)
% If DOUBLE CLICK
if (ev.getClickCount() == 2)
% Rename selection
EditElectrodeLabel();
end
end
end
%% =================================================================================
% === EXTERNAL PANEL CALLBACKS ===================================================
% =================================================================================
%% ===== CURRENT FIGURE CHANGED =====
function CurrentFigureChanged_Callback(hFig) %#ok<DEFNU>
UpdatePanel();
end
%% ===== UPDATE CALLBACK =====
function UpdatePanel()
% Get panel controls
ctrl = bst_get('PanelControls', 'iEEG');
if isempty(ctrl)
return;
end
% Get current electrodes
[sElectrodes, iDS, iFig, hFig] = GetElectrodes();
% If a surface is available for current figure
if ~isempty(hFig)
gui_enable([ctrl.jPanelElecList, ctrl.jToolbar], 1);
ctrl.jListElec.setBackground(java.awt.Color(1,1,1));
% Else: no figure associated with the panel : disable all controls
else
gui_enable([ctrl.jPanelElecList, ctrl.jToolbar], 0);
ctrl.jListElec.setBackground(java.awt.Color(.9,.9,.9));
end
% Select appropriate display mode button
if ~isempty(hFig)
ElectrodeDisplay = getappdata(hFig(1), 'ElectrodeDisplay');
if strcmpi(ElectrodeDisplay.DisplayMode, 'depth')
ctrl.jRadioDispDepth.setSelected(1);
else
ctrl.jRadioDispSphere.setSelected(1);
end
end
% % Disable options panel until an electrode is selected
% gui_enable(ctrl.jPanelElecOptions, 0);
% Update JList
UpdateElecList();
end
%% ===== UPDATE ELECTRODE LIST =====
function UpdateElecList()
import org.brainstorm.list.*;
% Get current electrodes
sElectrodes = GetElectrodes();
% Get panel controls
ctrl = bst_get('PanelControls', 'iEEG');
if isempty(ctrl)
return;
end
% Remove temporarily the list callback
callbackBak = java_getcb(ctrl.jListElec, 'ValueChangedCallback');
java_setcb(ctrl.jListElec, 'ValueChangedCallback', []);
% Get selected electrodes
iSelElec = ctrl.jListElec.getSelectedIndex() + 1;
SelName = char(ctrl.jListElec.getSelectedValue());
if (iSelElec == 0) || (iSelElec > length(sElectrodes)) || ~strcmpi(sElectrodes(iSelElec).Name, SelName)
SelName = [];
end
% Create a new empty list
listModel = java_create('javax.swing.DefaultListModel');
% Get font with which the list is rendered
fontSize = round(11 * bst_get('InterfaceScaling') / 100);
jFont = java.awt.Font('Dialog', java.awt.Font.PLAIN, fontSize);
tk = java.awt.Toolkit.getDefaultToolkit();
% Add an item in list for each electrode
Wmax = 0;
iSelElecNew = [];
for i = 1:length(sElectrodes)
% itemType = num2str(sElectrodes(i).ContactNumber);
itemType = '';
if sElectrodes(i).Visible
itemText = sElectrodes(i).Name;
itemColor = sElectrodes(i).Color;
else
itemText = ['<HTML><FONT color="#a0a0a0">' sElectrodes(i).Name '</FONT>'];
itemColor = [.63 .63 .63];
end
listModel.addElement(BstListItem(itemType, [], itemText, i, itemColor(1), itemColor(2), itemColor(3)));
% Get longest string
W = tk.getFontMetrics(jFont).stringWidth(sElectrodes(i).Name);
if (W > Wmax)
Wmax = W;
end
% Check if selected
if ~isempty(SelName) && strcmpi(sElectrodes(i).Name, SelName)
iSelElecNew = i;
end
end
% Update list model
ctrl.jListElec.setModel(listModel);
% Update cell rederer based on longest channel name
ctrl.jListElec.setCellRenderer(java_create('org.brainstorm.list.BstClusterListRenderer', 'II', fontSize, Wmax + 28));
% Select previously selected electrodes
if ~isempty(iSelElecNew)
ctrl.jListElec.setSelectedIndex(iSelElecNew - 1);
end
% Update electrode properties
UpdateElecProperties(0);
% Restore callback
drawnow;
java_setcb(ctrl.jListElec, 'ValueChangedCallback', callbackBak);
end
%% ===== UPDATE MODEL LIST =====
function UpdateModelList(elecType)
import org.brainstorm.list.*;
% Get panel controls
ctrl = bst_get('PanelControls', 'iEEG');
if isempty(ctrl)
return;
end
% Get the available electrode models
sModels = GetElectrodeModels();
% Show only the models from the selected modality
if ~isempty(elecType)
switch (elecType)
case 'SEEG'
iMod = find(strcmpi({sModels.Type}, 'SEEG'));
case {'ECOG', 'ECOG-mid'}
iMod = find(strcmpi({sModels.Type}, 'ECOG'));
end
sModels = sModels(iMod);
end
% Sort names alphabetically
elecModels = sort({sModels.Model});
% Save combobox callback
jModel = ctrl.jComboModel.getModel();
bakCallback = java_getcb(jModel, 'ContentsChangedCallback');
java_setcb(jModel, 'ContentsChangedCallback', []);
% Empty the ComboBox
ctrl.jComboModel.removeAllItems();
% Add all entries in the combo box
ctrl.jComboModel.addItem(BstListItem('', '', '', 0));
for i = 1:length(elecModels)
ctrl.jComboModel.addItem(BstListItem('', '', elecModels{i}, i));
end
% Restore callback
java_setcb(jModel, 'ContentsChangedCallback', bakCallback);
end
%% ===== UPDATE ELECTRODE PROPERTIES =====
function UpdateElecProperties(isUpdateModelList)
% Parse inputs
if (nargin < 1) || isempty(isUpdateModelList)
isUpdateModelList = 1;
end
% Get panel controls
ctrl = bst_get('PanelControls', 'iEEG');
if isempty(ctrl)
return;
end
% Get selected electrodes
[sSelElec, iSelElec] = GetSelectedElectrodes();
% Enable panel if something is selected
gui_enable(ctrl.jPanelElecOptions, ~isempty(sSelElec));
% Select ECOG/SEEG
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).Type), {sSelElec.Type})))
if strcmpi(sSelElec(1).Type, 'SEEG')
ctrl.jRadioSeeg.setSelected(1);
elecType = 'SEEG';
elseif strcmpi(sSelElec(1).Type, 'ECOG')
ctrl.jRadioEcog.setSelected(1);
elecType = 'ECOG';
elseif strcmpi(sSelElec(1).Type, 'ECOG-mid')
ctrl.jRadioEcogMid.setSelected(1);
elecType = 'ECOG-mid';
else
elecType = [];
end
else
ctrl.jRadioSeeg.setSelected(0);
ctrl.jRadioEcog.setSelected(0);
ctrl.jRadioEcogMid.setSelected(0);
elecType = [];
end
% Update list of models
if isUpdateModelList
% Update list of electrode models
UpdateModelList(elecType);
% Select electrode model
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).Model), {sSelElec.Model})))
SetSelectedModel(sSelElec(1).Model);
else
SetSelectedModel([]);
end
end
% Update control labels
if ~isempty(sSelElec) && strcmpi(sSelElec(1).Type, 'SEEG')
ctrl.jLabelContactLength.setText('Contact length: ');
ctrl.jLabelElecLength.setVisible(1);
ctrl.jTextElecLength.setVisible(1);
ctrl.jLabelElecLengthUnits.setVisible(1);
ctrl.jLabelElecDiameter.setText('Electrode diameter: ');
ctrl.jLabelElecDiamUnits.setText(' mm');
else
ctrl.jLabelContactLength.setText('Contact height: ');
ctrl.jLabelElecLength.setVisible(0);
ctrl.jTextElecLength.setVisible(0);
ctrl.jLabelElecLengthUnits.setVisible(0);
ctrl.jLabelElecDiameter.setText('Wire width: ');
ctrl.jLabelElecDiamUnits.setText(' points');
end
% Number of contacts
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).ContactNumber), {sSelElec.ContactNumber})))
valContacts = sSelElec(1).ContactNumber;
else
valContacts = [];
end
% Contact spacing
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).ContactSpacing), {sSelElec.ContactSpacing})))
valSpacing = sSelElec(1).ContactSpacing * 1000;
else
valSpacing = [];
end
% Contact length
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).ContactLength), {sSelElec.ContactLength})))
valContactLength = sSelElec(1).ContactLength * 1000;
else
valContactLength = [];
end
% Contact diameter
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).ContactDiameter), {sSelElec.ContactDiameter})))
valContactDiam = sSelElec(1).ContactDiameter * 1000;
else
valContactDiam = [];
end
% Electrode diameter
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).ElecDiameter), {sSelElec.ElecDiameter})))
valElecDiameter = sSelElec(1).ElecDiameter * 1000;
else
valElecDiameter = [];
end
% Electrode length
if (length(sSelElec) == 1) || ((length(sSelElec) > 1) && all(cellfun(@(c)isequal(c,sSelElec(1).ElecLength), {sSelElec.ElecLength})))
valElecLength = sSelElec(1).ElecLength * 1000;
else
valElecLength = [];
end
% Update panel
gui_validate_text(ctrl.jTextNcontacts, [], [], {1,1024,1}, 'list', 0, valContacts, @(h,ev)ValidateOptions('ContactNumber', ctrl.jTextNcontacts));
gui_validate_text(ctrl.jTextSpacing, [], [], {0,100,100}, 'optional', 2, valSpacing, @(h,ev)ValidateOptions('ContactSpacing', ctrl.jTextSpacing));
gui_validate_text(ctrl.jTextContactLength, [], [], {0,30,100}, 'optional', 2, valContactLength, @(h,ev)ValidateOptions('ContactLength', ctrl.jTextContactLength));
gui_validate_text(ctrl.jTextContactDiam, [], [], {0,20,100}, 'optional', 2, valContactDiam, @(h,ev)ValidateOptions('ContactDiameter', ctrl.jTextContactDiam));
gui_validate_text(ctrl.jTextElecDiameter, [], [], {0,20,100}, 'optional', 2, valElecDiameter, @(h,ev)ValidateOptions('ElecDiameter', ctrl.jTextElecDiameter));
gui_validate_text(ctrl.jTextElecLength, [], [], {0,200,100}, 'optional', 2, valElecLength, @(h,ev)ValidateOptions('ElecLength', ctrl.jTextElecLength));
% Update button list
if (length(sSelElec) == 1)
colorOn = java.awt.Color(0, 0.8, 0);
colorOff = java.awt.Color(0, 0, 0);
colorNone= java.awt.Color(.4, .4, .4);
if strcmpi(sSelElec(1).Type, 'SEEG')
ctrl.jCardLayout.show(ctrl.jPanelButtons, 'seeg');
if (size(sSelElec.Loc,2) >= 1)
ctrl.jButtonSeegSet1.setForeground(colorOn);
else
ctrl.jButtonSeegSet1.setForeground(colorOff);
end
if (size(sSelElec.Loc,2) >= 2)
ctrl.jButtonSeegSet2.setForeground(colorOn);
else
ctrl.jButtonSeegSet2.setForeground(colorOff);
end
else
ctrl.jCardLayout.show(ctrl.jPanelButtons, 'ecog');
if (size(sSelElec.Loc,2) >= 1)
ctrl.jButtonEcogSet1.setForeground(colorOn);
else
ctrl.jButtonEcogSet1.setForeground(colorOff);
end
if (size(sSelElec.Loc,2) >= 2)
ctrl.jButtonEcogSet2.setForeground(colorOn);
else
ctrl.jButtonEcogSet2.setForeground(colorOff);
end
if (length(valContacts) >= 2)
ctrl.jButtonEcogSet3.setEnabled(1);
ctrl.jButtonEcogSet4.setEnabled(1);
if (size(sSelElec.Loc,2) >= 3)
ctrl.jButtonEcogSet3.setForeground(colorOn);
else
ctrl.jButtonEcogSet3.setForeground(colorOff);
end
if (size(sSelElec.Loc,2) >= 4)
ctrl.jButtonEcogSet4.setForeground(colorOn);
else
ctrl.jButtonEcogSet4.setForeground(colorOff);
end
else
ctrl.jButtonEcogSet3.setEnabled(0);
ctrl.jButtonEcogSet4.setEnabled(0);
ctrl.jButtonEcogSet3.setForeground(colorNone);
ctrl.jButtonEcogSet4.setForeground(colorNone);
end
end
else
ctrl.jCardLayout.show(ctrl.jPanelButtons, 'none');
end
% Select show button
isSelected = ~isempty(sSelElec) && all([sSelElec.Visible] == 1);
ctrl.jButtonShow.setSelected(isSelected);
% Save selected electrodes
ctrl.jLabelSelectElec.setText(num2str(iSelElec));
end
%% ===== GET SELECTED ELECTRODES =====
function [sSelElec, iSelElec, iDS, iFig, hFig] = GetSelectedElectrodes()
sSelElec = [];
iSelElec = [];
iDS = [];
iFig = [];
hFig = [];
% Get panel handles
ctrl = bst_get('PanelControls', 'iEEG');
if isempty(ctrl)
return;
end
% Get all electrodes
[sElectrodes, iDS, iFig, hFig] = GetElectrodes();
if isempty(sElectrodes)
return
end
% Get JList selected indices
iSelElec = uint16(ctrl.jListElec.getSelectedIndices())' + 1;
sSelElec = sElectrodes(iSelElec);
end
%% ===== SET SELECTED ELECTRODES =====
% USAGE: SetSelectedElectrodes(iSelElec) % array of indices
% SetSelectedElectrodes(SelElecNames) % cell array of names
function SetSelectedElectrodes(iSelElec)
% === GET ELECTRODE INDICES ===
% Get figure controls
ctrl = bst_get('PanelControls', 'iEEG');
if isempty(ctrl) || isempty(ctrl.jListElec)
return
end
% No selection
if isempty(iSelElec) || (isnumeric(iSelElec) && any(iSelElec == 0))
iSelItem = -1;
% Select by name
elseif iscell(iSelElec) || ischar(iSelElec)
% Get list of electrode names
if iscell(iSelElec)
SelElecNames = iSelElec;
else
SelElecNames = {iSelElec};
end
% Find the requested channels in the JList
listModel = ctrl.jListElec.getModel();
iSelItem = [];
for i = 1:listModel.getSize()
if ismember(char(listModel.getElementAt(i-1)), SelElecNames)
iSelItem(end+1) = i - 1;
end
end
if isempty(iSelItem)
iSelItem = -1;
end
% Find the selected electrode in the JList
else
iSelItem = iSelElec - 1;
end
% === CHECK FOR MODIFICATIONS ===
% Get previous selection
iPrevItems = ctrl.jListElec.getSelectedIndices();
% If selection did not change: exit
if isequal(iPrevItems, iSelItem) || (isempty(iPrevItems) && isequal(iSelItem, -1))
return
end
% === UPDATE SELECTION ===
% Temporality disables JList selection callback
jListCallback_bak = java_getcb(ctrl.jListElec, 'ValueChangedCallback');
java_setcb(ctrl.jListElec, 'ValueChangedCallback', []);
% Select items in JList
ctrl.jListElec.setSelectedIndices(iSelItem);
% Scroll to see the last selected electrode in the list
if (length(iSelItem) >= 1) && ~isequal(iSelItem, -1)
selRect = ctrl.jListElec.getCellBounds(iSelItem(end), iSelItem(end));
ctrl.jListElec.scrollRectToVisible(selRect);
ctrl.jListElec.repaint();
end
% Restore JList callback
java_setcb(ctrl.jListElec, 'ValueChangedCallback', jListCallback_bak);
% Update panel fields
UpdateElecProperties();
end
%% ===== SHOW CONTACTS MENU =====
function ShowContactsMenu(jButton)
import org.brainstorm.icon.*;
% Create popup menu
jMenu = java_create('javax.swing.JPopupMenu');
% Get selected electrode
[sSelElec, iSelElec, iDS, iFig] = GetSelectedElectrodes();
if isempty(iSelElec)
java_dialog('warning', 'No electrode selected.', 'Align contacts');
return
end
% Menu: Default positions
gui_component('MenuItem', jMenu, [], 'Use default positions', IconLoader.ICON_SEEG_DEPTH, [], @(h,ev)bst_call(@AlignContacts, iDS, iFig, 'default'));
% Menu: Export select atlas
if strcmpi(sSelElec(1).Type, 'ECOG')
gui_component('MenuItem', jMenu, [], 'Project on inner skull', IconLoader.ICON_SEEG_DEPTH, [], @(h,ev)bst_call(@ProjectContacts, iDS(1), iFig(1), 'innerskull'));
gui_component('MenuItem', jMenu, [], 'Project on cortex', IconLoader.ICON_SEEG_DEPTH, [], @(h,ev)bst_call(@ProjectContacts, iDS(1), iFig(1), 'cortexmask'));
elseif strcmpi(sSelElec(1).Type, 'SEEG')
gui_component('MenuItem', jMenu, [], 'Project on electrode', IconLoader.ICON_SEEG_DEPTH, [], @(h,ev)bst_call(@AlignContacts, iDS, iFig, 'project'));
end
% Menu: Save modifications
jMenu.addSeparator();
gui_component('MenuItem', jMenu, [], 'Save modifications', IconLoader.ICON_SAVE, [], @(h,ev)bst_call(@bst_memory, 'SaveChannelFile', iDS(1)));
% Menu: Export positions
jMenu.addSeparator();
gui_component('MenuItem', jMenu, [], 'Export contacts positions', IconLoader.ICON_SAVE, [], @(h,ev)bst_call(@ExportChannelFile, 0));
gui_component('MenuItem', jMenu, [], 'Compute atlas labels', IconLoader.ICON_VOLATLAS, [], @(h,ev)bst_call(@ExportChannelFile, 1));
% Show popup menu
gui_brainstorm('ShowPopup', jMenu, jButton);
end
%% ===== GET COLOR TABLE =====
function ColorTable = GetElectrodeColorTable()
ColorTable = [0 .8 0 ;
1 0 0 ;
.4 .4 1 ;
1 .694 .392;
0 1 1 ;
1 0 1 ;
.4 0 0 ;
0 .4 0 ;
1 .843 0 ];
end
%% ===== EDIT ELECTRODE LABEL =====
% Rename one selected electrode
function EditElectrodeLabel(varargin)
global GlobalData;
% Get selected electrodes
[sSelElec, iSelElec, iDS, iFig] = GetSelectedElectrodes();
% Get all electrodes
sAllElec = GetElectrodes();
% Warning message if no electrode selected
if isempty(sAllElec)
java_dialog('warning', 'No electrodes selected.', 'Rename selected electrodes');
return;
% If more than one electrode selected: keep only the first one
elseif (length(sSelElec) > 1)
iSelElec = iSelElec(1);
sSelElec = sSelElec(1);
SetSelectedElectrodes(iSelElec);
end
% Ask user for a new label
newLabel = java_dialog('input', sprintf('Enter a new label for electrode "%s":', sSelElec.Name), ...
'Rename selected electrode', [], sSelElec.Name);
if isempty(newLabel) || strcmpi(newLabel, sSelElec.Name)
return
end
% Check if if already exists
if any(strcmpi({sAllElec.Name}, newLabel))
java_dialog('warning', ['Electrode "' newLabel '" already exists.'], 'Rename selected electrode');
return;
% Check that name do not include a digit
elseif any(ismember(newLabel, '0123456789:;*=?!<>"`&%$()[]{}/\_@ áÁàÀâÂäÄãÃåÅæÆçÇéÉèÈêÊëËíÍìÌîÎïÏñÑóÓòÒôÔöÖõÕøØßúÚùÙûÛüÜ'))
java_dialog('warning', 'New electrode name should not include digits, spaces or special characters.', 'Rename selected electrode');
return;
end
% Update electrode definition
oldLabel = sSelElec.Name;
sSelElec.Name = newLabel;
% Save modifications
SetElectrodes(iSelElec, sSelElec);
% Update JList
UpdateElecList();
% Select again electrode
SetSelectedElectrodes(iSelElec);
% Get the channel names to update
iDSchan = iDS(1);
iChan = find(strcmp({GlobalData.DataSet(iDSchan).Channel.Group}, oldLabel));
% Rename all the corresponding data channels
for i = 1:length(iChan)
% Check that the channel has really the old name in its label
chName = GlobalData.DataSet(iDSchan).Channel(iChan(i)).Name;
if (length(chName) <= length(oldLabel)) || ~strcmp(chName(1:length(oldLabel)), oldLabel)
disp(['BST> Channel "' chName '" does not match the name of the group "' oldLabel '": Not reaming to "' newName '"...']);
continue;
end
% Check that new channel name does not exist yet
newName = [newLabel, chName(length(oldLabel)+1:end)];
if any(strcmpi(newName, {GlobalData.DataSet(iDSchan).Channel.Name}))
disp(['BST> Channel "' chName '" cannot be renamed: a channel named "' newName '" already exists.']);
continue;
end
% Update channel group
GlobalData.DataSet(iDSchan).Channel(iChan(i)).Group = newLabel;
% Update channel name
GlobalData.DataSet(iDSchan).Channel(iChan(i)).Name = newName;
end
% Update figures
UpdateFigures();
end
%% ===== EDIT ELECTRODE COLOR =====
function EditElectrodeColor(newColor)
% Get selected electrode
[sSelElec, iSelElec] = GetSelectedElectrodes();
if isempty(iSelElec)
java_dialog('warning', 'No electrode selected.', 'Edit electrode color');
return
end
% If color is not specified in argument : ask it to user
if (nargin < 1)
% Use previous electrode color
% newColor = uisetcolor(sSelElec(1).Color, 'Select electrode color');
newColor = java_dialog('color');
% If no color was selected: exit
if (length(newColor) ~= 3) || all(sSelElec(1).Color == newColor)
return
end
end
% Update electrode color
for i = 1:length(sSelElec)
sSelElec(i).Color = newColor;
end
% Save electrodes
SetElectrodes(iSelElec, sSelElec);
% Update electrodes list
UpdateElecList();
% Select again electrode
SetSelectedElectrodes(iSelElec);
% Update figures
UpdateFigures();
end
%% ===== VALIDATE OPTIONS =====
function ValidateOptions(optName, jControl)
global GlobalData;
% Get figure controls
ctrl = bst_get('PanelControls', 'iEEG');
if isempty(ctrl) || isempty(ctrl.jListElec)
return
end
% Get all electrodes
[sElectrodes, iDSall, iFigall] = GetElectrodes();
if isempty(sElectrodes)
return
end
% Get the previously selected electrodes (otherwise it updates the newly selected electrode)
iSelElec = str2num(ctrl.jLabelSelectElec.getText());
if isempty(iSelElec)
return;
end
sSelElec = sElectrodes(iSelElec);
isModified = 0;
isChannelModified = 0;
% Get new value
if strcmpi(optName, 'Type')
val = char(jControl.getText());
elseif strcmpi(optName, 'ContactNumber')
val = round(str2num(jControl.getText()));
% SEEG electrode can have only one dimension, others two dimensions max
if (length(val) >= 2) && strcmpi(sElectrodes(iSelElec).Type, 'SEEG')
val = val(1);
jControl.setText(sprintf('%d', val));
elseif (length(val) >= 3)
val = val(1:2);
jControl.setText(sprintf('%d ', val));
end
else
val = str2num(jControl.getText()) / 1000;
end
% If setting multiple contacts: do not accept [] as a valid entry
if isempty(val) && (length(sSelElec) > 1)
return;
end
% Update field for all the selected electrodes
for iElec = 1:length(sSelElec)
if ~isequal(sSelElec(iElec).(optName), val)
% Update electrode definition
sSelElec(iElec).(optName) = val;
isModified = 1;
% If changing electrode type: update all channel types
if strcmpi(optName, 'Type')
% Loop on datasets
for iDS = unique(iDSall)
% Get contacts for this electrode
iChan = find(strcmpi({GlobalData.DataSet(iDS).Channel.Group}, sSelElec(iElec).Name));
if isempty(iChan)
continue;
end
% Update the channels types
switch (val)
case 'SEEG'
[GlobalData.DataSet(iDS).Channel(iChan).Type] = deal('SEEG');
case {'ECOG', 'ECOG-mid'}
[GlobalData.DataSet(iDS).Channel(iChan).Type] = deal('ECOG');
end
end
isChannelModified = 1;
end
end
end
% Save electrodes
if isModified
SetElectrodes(iSelElec, sSelElec);
% Update iEEG panel if needed
if ismember(optName, {'Type', 'ContactNumber'})
UpdateElecProperties(1);
end
% Mark channel file as modified (only the first one)
if isChannelModified
GlobalData.DataSet(iDSall(1)).isChannelModified = 1;
end
% Update figures
UpdateFigures();
% Update figure modalities
for i = 1:length(iDSall)
UpdateFigureModality(iDSall(i), iFigall(i));
end
end
end
%% ===== SHOW/HIDE ELECTRODE =====
function SetElectrodeVisible(isVisible)
% Get selected electrode
[sSelElec, iSelElec] = GetSelectedElectrodes();
if isempty(iSelElec)
java_dialog('warning', 'No electrode selected.', 'Show/hide electrode');
return
end
% Update electrode color
for i = 1:length(sSelElec)
sSelElec(i).Visible = isVisible;
end
% Save electrodes
SetElectrodes(iSelElec, sSelElec);
% Update electrodes list
UpdateElecList();
% Select again electrode
SetSelectedElectrodes(iSelElec);
% Update figures
UpdateFigures();
end
%% ===== GET ELECTRODES =====
function [sElectrodes, iDSall, iFigall, hFigall] = GetElectrodes()
global GlobalData;
% Get current figure
[hFigall,iFigall,iDSall] = bst_figures('GetCurrentFigure');
% Check if there are electrodes defined for this file
if isempty(hFigall) || isempty(GlobalData.DataSet(iDSall).IntraElectrodes) || isempty(GlobalData.DataSet(iDSall).ChannelFile)
sElectrodes = [];
return;
end
% Return all the available electrodes
sElectrodes = GlobalData.DataSet(iDSall).IntraElectrodes;
ChannelFile = GlobalData.DataSet(iDSall).ChannelFile;
% Get all the figures that share this channel file
for iDS = 1:length(GlobalData.DataSet)
% Skip if not the correct channel file
if ~file_compare(GlobalData.DataSet(iDS).ChannelFile, ChannelFile)
continue;
end
% Get all the figures
for iFig = 1:length(GlobalData.DataSet(iDS).Figure)
if ((iDS ~= iDSall(1)) || (iFig ~= iFigall(1))) && ismember(GlobalData.DataSet(iDS).Figure(iFig).Id.Type, {'MriViewer', '3DViz', 'Topography'})
iDSall(end+1) = iDS;
iFigall(end+1) = iFig;
hFigall(end+1) = GlobalData.DataSet(iDS).Figure(iFig).hFigure;
end
end
end
end
%% ===== SET ELECTRODES =====
% USAGE: iElec = SetElectrodes(iElec=[], sElect)
% iElec = SetElectrodes('Add', sElect)
function iElec = SetElectrodes(iElec, sElect)
global GlobalData;
% Parse input
isAdd = ~isempty(iElec) && ischar(iElec) && strcmpi(iElec, 'Add');
% Get dataset
[sElecOld, iDSall] = GetElectrodes();
% If there is no selected dataset