Opticka 2.16.1
Opticka is an experiment manager for behavioral research.
Loading...
Searching...
No Matches
baseStimulus Class Reference

baseStimulus is the superclass for all stimulus objects More...

Detailed Description

baseStimulus is the superclass for all stimulus objects

Superclass providing basic structure for all stimulus classes. This is a dynamic properties descendant, allowing for the temporary run variables used, which get appended "name"Out, i.e. speed is duplicated to a dymanic property called speedOut; it is the dynamic propertiy which is used during runtime, and whose values are converted from definition units like degrees to pixel values that PTB uses. The transient copies are generated on setup and removed on reset.

Todo:
build up animatorManager functions

Copyright ©2014-2022 Ian Max Andolina — released: LGPL3, see LICENCE.md

Inheritance diagram for baseStimulus:

Public Types

enum  Events { readPanelUpdate }
 

Public Member Functions

virtual setup (in runObject)
 ALL Children must implement these 5 methods!
 
virtual draw (in runObject)
 draw to the screen buffer, ready for flip()
 
virtual animate (in runObject)
 animate the stimulus, normally called after a draw
 
virtual update (in runObject)
 
virtual reset (in runObject)
 
function baseStimulus (in varargin)
 Class constructor.
 
function set colour (in me, in value)
 colour set method Allow 1 (R=G=B) 3 (RGB) or 4 (RGBA) value colour
 
function set alpha (in me, in value)
 alpha set method
 
function get delta (in me)
 delta Get method delta is the normalised number of pixels per frame to move a stimulus
 
function get dX (in me)
 dX Get method X position increment for a given delta and angle
 
function get dY (in me)
 dY Get method Y position increment for a given delta and angle
 
function show (in me)
 Method to set isVisible=true.
 
function hide (in me)
 Method to set isVisible=false.
 
function setOffTime (in me, in time)
 set offTime
 
function setDelayTime (in me, in time)
 set delayTime
 
function resetTicks (in me)
 reset the various tick counters for our stimulus
 
function getMousePosition (in me)
 get mouse position we make sure this is only called once per animation tick to improve performance and ensure all stimuli that are following mouse position have consistent X and Y per frame update This sets mouseX and mouseY and mouseValid if mouse is within PTB screen (useful for mouse override positioning for stimuli)
 
function run (in me, in benchmark, in runtime, in s, in forceScreen, in showVBL)
 Run stimulus in a window to preview it.
 
function makePanel (in me, in parent)
 make a GUI properties panel for this object
 
function selectFilePanel (in me, in varargin)
 read values from a GUI properties panel for this object
 
function readPanel (in me, in varargin)
 read values from a GUI properties panel for this object
 
function showPanel (in me)
 show GUI properties panel for this object
 
function hidePanel (in me)
 hide GUI properties panel for this object
 
function closePanel (in me, in varargin)
 close GUI panel for this object
 
function cleanHandles (in me, in ignoredArg)
 clean any handles
 
function getP (in me, in name, in range)
 gets a property copy or original property
 
function setP (in me, in name, in value)
 sets a property copy or original property
 
function updateXY (in me, in x, in y, in useDegrees)
 Update only position info, faster and doesn't reset image etc.
 
- Public Member Functions inherited from optickaCore
function optickaCore (in varargin)
 Class constructor.
 
function get fullName (in me)
 
function getALF (in me, in subject, in sessionPrefix, in lab, in create)
 
function findAttributes (in me, in attrName, in attrValue)
 
function findAttributesandType (in me, in attrName, in attrValue, in type)
 find properties of object with specific attributes, for example all properties whose GetAcccess attribute is public and type is logical.
 
function findPropertyDefault (in me, in propName)
 
function clone (in me)
 Use this syntax to make a deep copy of the object, i.e. OBJ_OUT has the same field values, but will not behave as a handle-copy of me anymore.
 
function checkSuperclasses (in List)
 
function editProperties (in me, in properties)
 method to modify a set of properties
 
function setProp (in me, in property, in value)
 method to fast change a particular value. This is useful for use in anonymous functions, like in the state machine.
 
function initialiseGlobals (in me, in doReset, in doOpen)
 
function initialiseSaveFile (in me)
 Initialise Save prefix.
 
function checkPaths (in me)
 checks the paths are valid
 

Static Public Member Functions

static function d2r (in degrees)
 degrees2radians
 
static function r2d (in r)
 radians2degrees
 
static function findDistance (in x1, in y1, in x2, in y2)
 findDistance in X and Y coordinates
 
static function updatePosition (in delta, in angle)
 updatePosition returns dX and dY given an angle and delta
 
- Static Public Member Functions inherited from optickaCore
static function makeArgs (in args)
 Converts cell args to structure array.
 
static function addDefaults (in args, in defs)
 add default options to arg input
 
static function hasKey (in in, in key)
 check if a struct / object has a propery / field
 
static function getKeys (in device)
 PTB Get key presses, stops key bouncing.
 

Public Attributes

Property type
 stimulus type
 
Property xPosition
 
Property yPosition
 
Property size
 
Property colour
 
Property alpha
 Alpha (opacity) [0-1], this gets combined with the RGB colour.
 
Property startPosition
 
Property speed
 
Property angle
 angle in degrees (0 - 360)
 
Property delayTime
 
Property offTime
 time to turn stimulus off, relative to stimulus onset
 
Property isVisible
 true or false, whether to draw() this object
 
Property mouseOverride
 override X and Y position with mouse input? Useful for RF mapping
 
Property showOnTracker
 show the position on the Eyetracker display?
 
Property verbose
 Do we log extra details to the command-line?
 
Property xFinal
 
Property yFinal
 
Property mvRect
 
Property szIsPx
 
Property szPx
 computed size in pixels
 
Property szD
 computed size in °
 
Property xFinalD
 X and Y position in °
 
Property yFinalD
 
Property isRect
 
Property tick
 tick updates +1 on each call of draw (even if delay or off is true and no stimulus is drawn, resets on each update
 
Property drawTick
 draw tick only updates when a draw is actually performed, resets on each update
 
Property ppd
 pixels per degree (normally inhereted from screenManager)
 
Property delta
 What our per-frame motion delta is.
 
Property dX
 X update which is computed from our speed and angle.
 
Property dY
 X update which is computed from our speed and angle.
 
- Public Attributes inherited from optickaCore
Property name
 object name
 
Property comment
 comment
 
Property verbose
 verbose logging, subclasses must assign this. This is normally logical true/false
 
Property dateStamp
 clock() dateStamp set on construction
 
Property uuid
 universal ID
 
Property paths
 storage of various paths
 
Property fullName
 The fullName is the object name combined with its uuid and class name.
 

Protected Member Functions

function addRuntimeProperties (in me)
 These are transient properties that specify actions during runtime.
 
function updateRuntimeProperties (in me)
 Update transient properties that specify actions during runtime.
 
function computePosition (in me)
 compute xFinal and yFinal (in pixels) taking startPosition, xPosition, yPosition and direction/angle into account
 
function setAnimationDelta (in me)
 
function setRect (in me)
 
function toStructure (in me, in tmp)
 Converts properties to a structure.
 
function removeTmpProperties (in me)
 Finds and removes dynamic properties.
 
function delete (in me)
 
- Protected Member Functions inherited from optickaCore
function parseArgs (in me, in args, in allowedProperties)
 Sets properties from a structure or normal arguments pairs, ignores invalid or non-allowed properties.
 
function addArgs (in me, in args)
 
function setPaths (in me)
 Sets properties from a structure or normal arguments pairs, ignores invalid or non-allowed properties.
 
function getFonts (in me)
 set paths for object
 
function toStructure (in me)
 Converts properties to a structure.
 
function getType (in me, in in)
 
function logOutput (in me, in in, in message, in override)
 Give a metaproperty return the likely property class.
 
function salutation (in me, in varargin)
 Prints messages dependent on verbosity.
 

Protected Attributes

Property family
 the stimulus family (grating, dots etc.)
 
Property texture
 Our texture pointer for texture-based stimuli.
 
Property handles
 handles for the GUI
 
Property sM
 our screen manager
 
Property animator
 animation manager
 
Property screenVals
 screen settings generated by sM on setup
 
Property isSetup
 
Property isGUI
 is panel constructed?
 
Property dstRect
 initial screen rectangle position [LEFT TOP RIGHT BOTTOM]
 
Property mouseValid
 is mouse position within screen co-ordinates?
 
Property mouseX
 mouse X position
 
Property mouseY
 mouse Y position
 
Property delayTicks
 delay ticks to wait until display
 
Property offTicks
 ticks before stimulus turns off
 
Property inSetup
 are we setting up?
 
Property delta_
 delta cache
 
Property dX_
 dX cache
 
Property dY_
 dY cache
 
Property isInSetColour
 deal with interaction of colour and alpha
 
Property setLoop
 
Property ignorePropertiesBase
 Which properties to ignore cloning when making transient copies in setup.
 
Property ignorePropertiesUIBase
 Which properties to not draw in the UI panel.
 
- Protected Attributes inherited from optickaCore
Property cloning
 are we cloning this from another object
 
Property mversion
 Matlab version number, this is transient so it is not saved.
 
Property sansFont
 sans font
 
Property monoFont
 monoFont
 
Property className
 class name
 
Property savePrefix
 save prefix generated from clock time
 
Property fullName_
 cached full name
 

Member Enumeration Documentation

◆ Events

Enumerator
readPanelUpdate 

triggered when reading from a UI panel,

251 :3) + me.colour2(1:3))/2;
252 end
253 me.isInSetColour = false;
254 end
255
256 % ===================================================================
257 %> @brief alpha set method
258 %>
259 % ===================================================================
260 function set.alpha(me,value)
261 if me.isSetup; warning('You should set alphaOut to affect drawing...'); end
262 if value<0; value=0;elseif value>1; value=1; end
263 me.alpha = value;
264 if ~me.isInSetColour
265 me.colour = me.colour(1:3); %force colour to be regenerated
266 if ~isempty(findprop(me,'colour2')) && ~isempty(me.colour2)
267 me.colour2 = [me.colour2(1:3) me.alpha];
268 end
269 if ~isempty(findprop(me,'baseColour')) && ~isempty(me.baseColour)
270 me.baseColour = [me.baseColour(1:3) me.alpha];
271 end
272 end
273 end
274
275 % ===================================================================
276 %> @brief delta Get method
277 %> delta is the normalised number of pixels per frame to move a stimulus
278 % ===================================================================
279 function value = get.delta(me)
280 value = (getP(me,'speed') * me.ppd) * me.screenVals.ifi;
281 end
282
283 % ===================================================================
284 %> @brief dX Get method
285 %> X position increment for a given delta and angle
286 % ===================================================================
287 function value = get.dX(me)
288 value = 0;
289 if ~isempty(findprop(me,'directionOut'))
290 [value,~]=me.updatePosition(me.delta,me.directionOut);
291 elseif ~isempty(findprop(me,'angleOut'))
292 [value,~]=me.updatePosition(me.delta,me.angleOut);
293 end
294 end
295
296 % ===================================================================
297 %> @brief dY Get method
298 %> Y position increment for a given delta and angle
299 % ===================================================================
300 function value = get.dY(me)
301 value = 0;
302 if ~isempty(findprop(me,'directionOut'))
303 [~,value]=me.updatePosition(me.delta,me.directionOut);
304 elseif ~isempty(findprop(me,'angleOut'))
305 [~,value]=me.updatePosition(me.delta,me.angleOut);
306 end
307 end
308
309 % ===================================================================
310 %> @brief Method to set isVisible=true.
311 %>
312 % ===================================================================
313 function show(me)
314 me.isVisible = true;
315 end
316
317 % ===================================================================
318 %> @brief Method to set isVisible=false.
319 %>
320 % ===================================================================
321 function hide(me)
322 me.isVisible = false;
323 end
324
325 % ===================================================================
326 %> @brief set offTime
327 %>
328 % ===================================================================
329 function setOffTime(me, time)
330 me.offTime = time;
331 end
332
333 % ===================================================================
334 %> @brief set delayTime
335 %>
336 % ===================================================================
337 function setDelayTime(me, time)
338 me.delayTime = time;
339 end
340
341 % ===================================================================
342 %> @brief reset the various tick counters for our stimulus
343 %>
344 % ===================================================================
345 function resetTicks(me)
346 global mouseTick %#ok<*GVMIS> %shared across all stimuli
347 if max(me.delayTime) > 0 %delay display a number of frames
348 if length(me.delayTime) == 1
349 me.delayTicks = round(me.delayTime/me.screenVals.ifi);
350 elseif length(me.delayTime) == 2
351 time = randi([me.delayTime(1)*1000 me.delayTime(2)*1000])/1000;
352 me.delayTicks = round(time/me.screenVals.ifi);
353 end
354 else
355 me.delayTicks = 0;
356 end
357 if min(me.offTime) < Inf %delay display a number of frames
358 if length(me.offTime) == 1
359 me.offTicks = round(me.offTime/me.screenVals.ifi);
360 elseif length(me.offTime) == 2
361 time = randi([me.offTime(1)*1000 me.offTime(2)*1000])/1000;
362 me.offTicks = round(time/me.screenVals.ifi);
363 end
364 else
365 me.offTicks = Inf;
366 end
367 mouseTick = 0;
368 me.tick = 0;
369 me.drawTick = 0;
370 end
371
372 % ===================================================================
373 %> @brief get mouse position
374 %> we make sure this is only called once per animation tick to
375 %> improve performance and ensure all stimuli that are following
376 %> mouse position have consistent X and Y per frame update
377 %> This sets mouseX and mouseY and mouseValid if mouse is within
378 %> PTB screen (useful for mouse override positioning for stimuli)
379 % ===================================================================
380 function getMousePosition(me)
381 global mouseTick mouseGlobalX mouseGlobalY mouseValid
382 if me.tick > mouseTick
383 if ~isempty(me.sM) && isa(me.sM,'screenManager') && me.sM.isOpen
384 [me.mouseX, me.mouseY] = GetMouse(me.sM.win);
385 else
386 [me.mouseX, me.mouseY] = GetMouse;
387 end
388 if me.mouseX > -1 && me.mouseY > -1
389 me.mouseValid = true;
390 else
391 me.mouseValid = false;
392 end
393 mouseTick = me.tick; %set global so no other object with same tick number can call this again
394 mouseValid = me.mouseValid;
395 mouseGlobalX = me.mouseX; mouseGlobalY = me.mouseY;
396 else
397 if ~isempty(mouseGlobalX) && ~isempty(mouseGlobalY)
398 me.mouseX = mouseGlobalX; me.mouseY = mouseGlobalY;
399 me.mouseValid = mouseValid;
400 end
401 end
402 end
403
404 % ===================================================================
405 %> @fn run
406 %> @brief Run stimulus in a window to preview it
407 %>
408 %> @param benchmark true|false [optional, default = false]
409 %> @param runtime time to show stimulus [optional, default = 2]
410 %> @param screenManager to use [optional]
411 %> @param forceScreen for a particulr monitor/screen to use
412 %> @param showVBL show a plot of the VBL times
413 % ===================================================================
414 function run(me, benchmark, runtime, s, forceScreen, showVBL)
415 % run(me, benchmark, runtime, s, forceScreen, showVBL)
416 try
417
418 if ~exist('benchmark','var') || isempty(benchmark)
419 benchmark=false;
420 end
421 if ~exist('runtime','var') || isempty(runtime)
422 runtime = 2; %seconds to run
423 end
424 if ~exist('s','var') || ~isa(s,'screenManager')
425 if isempty(me.sM); me.sM=screenManager; end
426 s = me.sM;
427 s.blend = true;
428 s.disableSyncTests = true;
429 s.visualDebug = true;
430 s.bitDepth = '8bit';
431 end
432 if ~exist('forceScreen','var') || isempty(forceScreen); forceScreen = -1; end
433 if ~exist('showVBL','var') || isempty(showVBL); showVBL = false; end
434
435 oldscreen = s.screen;
436 oldbitdepth = s.bitDepth;
437 oldwindowed = s.windowed;
438 if forceScreen >= 0
439 s.screen = forceScreen;
440 if forceScreen == 0
441 s.bitDepth = '8bit';
442 end
443 end
444 prepareScreen(s);
445
446 if benchmark
447 s.windowed = false;
448 elseif forceScreen > -1
449 if ~isempty(s.windowed) && (length(s.windowed) == 2 || length(s.windowed) == 4)
450 % use existing setting
451 else
452 s.windowed = [0 0 s.screenVals.screenWidth/2 s.screenVals.screenHeight/2]; %half of screen
453 end
454 end
455
456 if me.verbose; s.debug = true; end
457
458 if ~s.isOpen; open(s);end
459 sv = s.screenVals;
460 setup(me,s); %setup our stimulus object
461
462 Priority(MaxPriority(s.win)); %bump our priority to maximum allowed
463
464 if ~any(strcmpi(me.family,{'movie','revcor'})); draw(me); resetTicks(me); end
465 if benchmark
466 drawText(s, 'BENCHMARK: screen won''t update properly, see FPS in command window at end.');
467 else
468 drawGrid(s); %draw degree dot grid
469 drawScreenCenter(s);
470 drawText(s, ['Preview ALL with grid = ±1°; static for 1 seconds, then animate for ' num2str(runtime) ' seconds...'])
471 end
472 if ismethod(me,'resetLog'); resetLog(me); end
473 flip(s);
474 if ~any(strcmpi(me.family,{'movie','revcor'})); update(me); end
475 if benchmark
476 WaitSecs('YieldSecs',0.25);
477 else
478 WaitSecs('YieldSecs',2);
479 end
480 if runtime < sv.ifi; runtime = sv.ifi; end
481 nFrames = 0;
482 notFinished = true;
483 benchmarkFrames = floor(sv.fps * runtime);
484 vbl = zeros(benchmarkFrames+1,1);
485 startT = GetSecs; lastvbl = startT;
486 while notFinished
487 nFrames = nFrames + 1;
488 draw(me); %draw stimulus
489 if ~benchmark && s.debug; drawGrid(s); end
490 finishDrawing(s); %tell PTB/GPU to draw
491 animate(me); %animate stimulus, will be seen on next draw
492 if benchmark
493 Screen('Flip',s.win,0,2,2);
494 notFinished = nFrames < benchmarkFrames;
495 else
496 vbl(nFrames) = flip(s, lastvbl + sv.halfifi); %flip the buffer
497 lastvbl = vbl(nFrames);
498 % the calculation needs to take into account the
499 % first and last frame times, so we subtract ifi*2
500 notFinished = lastvbl < ( vbl(1) + ( runtime - (sv.ifi * 2) ) );
501 end
502 end
503 endT = flip(s);
504 if ~benchmark;startT = vbl(1);end
505 diffT = endT - startT;
506 WaitSecs(0.5);
507 vbl = vbl(1:nFrames);
508 if showVBL && ~benchmark
509 figure;
510 plot(diff(vbl)*1e3,'k*');
511 line([0 length(vbl)-1],[sv.ifi*1e3 sv.ifi*1e3],'Color',[0 0 0]);
512 title(sprintf('VBL Times, should be ~%.4f ms',sv.ifi*1e3));
513 ylabel('Time (ms)')
514 xlabel('Frame #')
515 end
516 Priority(0); ShowCursor; ListenChar(0);
517 reset(me); %reset our stimulus ready for use again
518 close(s); %close screen
519 s.screen = oldscreen;
520 s.windowed = oldwindowed;
521 s.bitDepth = oldbitdepth;
522 fps = nFrames / diffT;
523 fprintf('\n\n======>>> Stimulus: %s\n',me.fullName);
524 fprintf('======>>> <strong>SPEED</strong> (%i frames in %.3f secs) = <strong>%g</strong> fps\n\n',nFrames, diffT, fps);
525 if ~benchmark;fprintf('\b======>>> First - Last frame time: %.3f\n\n',vbl(end)-startT);end
526 clear s fps benchmark runtime b bb i vbl; %clear up a bit
527 catch ERR
528 try getReport(ERR); end
529 try Priority(0); end
530 if exist('s','var') && isa(s,'screenManager')
531 try close(s); end
532 end
533 clear fps benchmark runtime b bb i; %clear up a bit
534 reset(me); %reset our stimulus ready for use again
535 rethrow(ERR)
536 end
537 end
538
539 % ===================================================================
540 %> @brief make a GUI properties panel for this object
541 %>
542 % ===================================================================
543 function handles = makePanel(me, parent)
544 if ~isempty(me.handles) && isfield(me.handles, 'root') && isa(me.handles.root,'matlab.ui.container.Panel')
545 fprintf('---> Panel already open for %s\n', me.fullName);
546 return
547 end
548
549 handles = [];
550 setPaths(me); % refresh our paths for the current machine
551 if isempty(me.sansFont); getFonts(me); end
552
553 if ~exist('parent','var')
554 parent = uifigure('Tag','gFig',...
555 'Name', [me.fullName 'Properties'], ...
556 'Position', [ 10 10 800 500 ],...
557 'MenuBar', 'none', ...
558 'CloseRequestFcn', @me.closePanel, ...
559 'NumberTitle', 'off');
560 me.handles(1).parent = parent;
561 handles(1).parent = parent;
562 end
563
564 bgcolor = [0.95 0.95 0.95];
565 bgcoloredit = [1 1 1];
566 fsmall = 11;
567 fmed = 12;
568 handles.root = uipanel('Parent', parent,...
569 'Units', 'normalized',...
570 'Position', [0 0 1 1],...
571 'Title', me.fullName,...
572 'TitlePosition','centertop',...
573 'FontName', me.sansFont,...
574 'FontSize', fmed,...
575 'FontAngle', 'italic',...
576 'BackgroundColor', [0.94 0.94 0.94]);
577 handles.grid = uigridlayout(handles.root,[1 3]);
578 handles.grid1 = uigridlayout(handles.grid,'Padding',[5 5 5 5],'BackgroundColor',bgcolor);
579 handles.grid2 = uigridlayout(handles.grid,'Padding',[5 5 5 5],'BackgroundColor',bgcolor);
580 handles.grid.ColumnWidth = {'1x','1x',130};
581 handles.grid1.ColumnWidth = {'2x','1x'};
582 handles.grid2.ColumnWidth = {'2x','1x'};
583
584 idx = {'handles.grid1','handles.grid2','handles.grid3'};
585
586 disableList = 'fullName';
587
588 mc = metaclass(me);
589 pl = string({mc.PropertyList.Name});
590 d1 = {mc.PropertyList.Description};
591 d2 = {mc.PropertyList.DetailedDescription};
592 for i = 1:length(d1)
593 a = regexprep(d1{i},'^\s*>\s*','');
594 a = regexprep(a,'''','`');
595 b = d2{i};
596 if isempty(b)
597 dl{i} = string(a);
598 else
599 b = strsplit(b,'\n');
600 for j = 1:length(b)
601 b{j} = regexprep(b{j},'^\s*>\s*','');
602 b{j} = regexprep(b{j},'''','`');
603 end
604 dl{i} = string([{a} b(:)']);
605 end
606 end
607 pr = findAttributesandType(me,'SetAccess','public','notlogical');
608 pr = sort(pr);
609 igA = {}; igB = {};
610 val = findPropertyDefault(me,'ignorePropertiesUI');
611 if ~isempty(val)
612 igA = val;
613 elseif isprop(me,'ignorePropertiesUI')
614 igA = me.ignorePropertiesUI;
615 end
616 if isprop(me,'ignorePropertiesUIBase'); igB = findPropertyDefault(me,'ignorePropertiesUIBase'); end
617 if ischar(igA);igA = strsplit(igA,'|');end
618 if ischar(igB); igB = {'animator','fullName','mvRect','xFinal','yFinal','xFinalD','yFinalD'}; end
619 excl = [igA igB];
620 eidx = [];
621 for i = 1:length(pr)
622 if matches(pr{i}, excl)
623 eidx = [eidx i];
624 end
625 end
626 pr(eidx) = [];
627 lp = ceil(length(pr)/2);
628
629 pr2 = findAttributesandType(me,'SetAccess','public','logical');
630 pr2 = sort(pr2);
631 eidx = [];
632 for i = 1:length(pr2)
633 if matches(pr2{i},excl)
634 eidx = [eidx i];
635 end
636 end
637 pr2(eidx) = [];
638 lp2 = length(pr2);
639 if lp2 > 0; handles.grid3 = uigridlayout(handles.grid,[lp2 1],'Padding',[1 1 1 1],'BackgroundColor',bgcolor); end
640
641 for i = 1:2
642 for j = 1:lp
643 cur = lp*(i-1)+j;
644 if cur <= length(pr)
645 nm = pr{cur};
646 val = me.(nm);
647 % this gets descriptions
648 ix = find(pl == nm);
649 if ~isempty(ix)
650 desc = dl{ix};
651 else
652 desc = nm;
653 end
654 if ischar(val)
655 if isprop(me,[nm 'List'])
656 if strcmp(me.([nm 'List']),'filerequestor')
657 val = regexprep(val,'\s+',' ');
658 handles.([nm '_char']) = uieditfield(...
659 'Parent',eval(idx{i}),...
660 'Tag',[nm '_char'],...
661 'HorizontalAlignment','center',...
662 'ValueChangedFcn',@me.readPanel,...
663 'Value',val,...
664 'FontName',me.monoFont,...
665 'Tooltip', desc, ...
666 'BackgroundColor',bgcoloredit);
667 if ~isempty(regexpi(nm,disableList,'once'))
668 handles.([nm '_char']).Enable = false;
669 end
670 else
671 txt=findPropertyDefault(me,[nm 'List']);
672 if contains(val,txt)
673 handles.([nm '_list']) = uidropdown(...
674 'Parent',eval(idx{i}),...
675 'Tag',[nm '_list'],...
676 'Items',txt,...
677 'ValueChangedFcn',@me.readPanel,...
678 'Value',val,...
679 'Tooltip', desc, ...
680 'BackgroundColor',bgcolor);
681 if ~isempty(regexpi(nm,disableList,'once'))
682 handles.([nm '_list']).Enable = false;
683 end
684 else
685 handles.([nm '_list']) = uidropdown(...
686 'Parent',eval(idx{i}),...
687 'Tag',[nm '_list'],...
688 'Items',txt,...
689 'Tooltip', desc, ...
690 'ValueChangedFcn',@me.readPanel,...
691 'BackgroundColor',bgcolor);
692 end
693 end
694 else
695 val = regexprep(val,'\s+',' ');
696 handles.([nm '_char']) = uieditfield(...
697 'Parent',eval(idx{i}),...
698 'Tag',[nm '_char'],...
699 'HorizontalAlignment','center',...
700 'ValueChangedFcn',@me.readPanel,...
701 'Value',val,...
702 'Tooltip', desc, ...
703 'BackgroundColor',bgcoloredit);
704 if ~isempty(regexpi(nm,disableList,'once'))
705 handles.([nm '_char']).Enable = false;
706 end
707 end
708 elseif isnumeric(val)
709 val = num2str(val);
710 val = regexprep(val,'\s+',' ');
711 handles.([nm '_num']) = uieditfield('text',...
712 'Parent',eval(idx{i}),...
713 'Tag',[nm '_num'],...
714 'HorizontalAlignment','center',...
715 'Value',val,...
716 'Tooltip', desc, ...
717 'ValueChangedFcn',@me.readPanel,...
718 'FontName',me.monoFont,...
719 'BackgroundColor',bgcoloredit);
720 if ~isempty(regexpi(nm,disableList,'once'))
721 handles.([nm '_num']).Enable = false;
722 end
723 else
724 uilabel('Parent',eval(idx{i}),'Text','','BackgroundColor',bgcolor,'Enable','off');
725 end
726 if isprop(me,[nm 'List'])
727 if strcmp(me.([nm 'List']),'filerequestor')
728 handles.([nm '_button']) = uibutton(...
729 'Parent',eval(idx{i}),...
730 'HorizontalAlignment','left',...
731 'Text','Select file...',...
732 'FontName',me.sansFont,...
733 'Tag',[nm '_button'],...
734 'Tooltip', desc, ...
735 'Icon', [me.paths.root '/ui/images/edit.svg'],...
736 'ButtonPushedFcn', @me.selectFilePanel,...
737 'FontSize', 8);
738 else
739 uilabel(...
740 'Parent',eval(idx{i}),...
741 'HorizontalAlignment','left',...
742 'Text',nm,...
743 'FontName',me.sansFont,...
744 'FontSize', fsmall,...
745 'BackgroundColor',bgcolor);
746 end
747 else
748 uilabel(...
749 'Parent',eval(idx{i}),...
750 'HorizontalAlignment','left',...
751 'Text',nm,...
752 'FontName',me.sansFont,...
753 'FontSize', fsmall,...
754 'BackgroundColor',bgcolor);
755 end
756 else
757 uilabel('Parent',eval(idx{i}),'Text','','BackgroundColor',bgcolor,'Enable','off');
758 end
759 end
760 end
761 for j = 1:lp2
762 nm = pr2{j};
763 val = me.(nm);
764 % this gets descriptions
765 ix = find(pl == nm);
766 if ~isempty(ix)
767 desc = dl{ix};
768 else
769 desc = nm;
770 end
771 if j <= length(pr2)
772 handles.([nm '_bool']) = uicheckbox(...
773 'Parent',eval(idx{end}),...
774 'Tag',[nm '_bool'],...
775 'Text',nm,...
776 'Tooltip', desc, ...
777 'FontName',me.sansFont,...
778 'FontSize', fsmall,...
779 'ValueChangedFcn',@me.readPanel,...
780 'Value',val);
781 end
782 end
783 %handles.readButton = uibutton(...
784 % 'Parent',eval(idx{end}),...
785 % 'Tag','readButton',...%'Callback',@me.readPanel,...
786 % 'Text','Update');
787 me.handles = handles;
788 me.isGUI = true;
789 end
790
791 % ===================================================================
792 %> @brief read values from a GUI properties panel for this object
793 %>
794 % ===================================================================
795 function selectFilePanel(me,varargin)
796 if nargin > 0
797 hin = varargin{1};
798 if ishandle(hin)
799 [f,p] = uigetfile('*.*','Select File:');
800 re = regexp(get(hin,'Tag'),'(.+)_button','tokens','once');
801 hout = me.handles.([re{1} '_char']);
802 if ishandle(hout)
803 set(hout,'Value', [p f]);
804 me.readPanel(hout);
805 end
806 end
807 end
808 end
809
810 % ===================================================================
811 %> @brief read values from a GUI properties panel for this object
812 %>
813 % ===================================================================
814 function readPanel(me,varargin)
815 if isempty(me.handles) || ~(isfield(me.handles, 'root') && isa(me.handles.root,'matlab.ui.container.Panel'))
816 return
817 end
818 if isempty(varargin) || isempty(varargin{1}); return; end
819 source = varargin{1};
820 tag = source.Tag;
821 if isempty(tag); return; end
822 tagName = regexprep(tag,'_.+$','');
823 tagType = regexprep(tag,'^.+_','');
824
825 pList = findAttributes(me,'SetAccess','public'); %our public properties
826
827 if ~any(contains(pList,tagName)); return; end
828
829 switch tagType
830 case 'list'
831 me.(tagName) = source.Value;
832 case 'bool'
833 me.(tagName) = logical(source.Value);
834 case 'num'
835 me.(tagName) = str2num(source.Value);
836 case 'char'
837 me.(tagName) = source.Value;
838 otherwise
839 warning('Can''t set property');
840 end
841
842 if strcmpi(tagName,'name')
843 me.handles.fullName_char.Value = me.fullName;
844 me.handles.root.Title = me.fullName;
845 end
846
847 if strcmpi(tagName,'alpha')
848 me.handles.colour_num.Value = num2str(me.colour, '%g ');
849 if isprop(me,'colour2')
850 me.handles.colour2_num.Value = num2str(me.colour2, '%g ');
851 end
852 if isprop(me,'baseColour')
853 me.handles.baseColour_num.Value = num2str(me.baseColour, '%g ');
854 end
855 end
856
857 if strcmpi(tagName,'alpha2')
858 if isprop(me,'colour2');me.handles.colour2_num.Value = num2str(me.colour2, '%g ');end
859 end
860
861 if strcmpi(tagName,'colour')
862 me.handles.alpha_num.Value = num2str(me.alpha, '%g ');
863 if isprop(me,'correctBaseColour') && me.correctBaseColour
864 me.handles.baseColour_num.Value = num2str(me.baseColour, '%g ');
865 end
866 end
867
868 if strcmpi(tagName,'colour2')
869 if isprop(me,'alpha2');me.handles.alpha2_num.Value = num2str(me.alpha2, '%g ');end
870 if isprop(me,'correctBaseColour') && me.correctBaseColour
871 me.handles.baseColour_num.Value = num2str(me.baseColour, '%g ');
872 end
873 end
874
875 if strcmpi(tagName,'filePath') && isa(me,'imageStimulus')
876 me.checkfilePath();
877 end
878
879 notify(me,'readPanelUpdate');
880 end
881
882 % ===================================================================
883 %> @brief show GUI properties panel for this object
884 %>
885 % ===================================================================
886 function showPanel(me)
887 if isempty(me.handles)
888 return
889 end
890 set(me.handles.root,'Enable','on');
891 set(me.handles.root,'Visible','on');
892 end
893
894 % ===================================================================
895 %> @brief hide GUI properties panel for this object
896 %>
897 % ===================================================================
898 function hidePanel(me)
899 if isempty(me.handles)
900 return
901 end
902 set(me.handles.root,'Enable','off');
903 set(me.handles.root,'Visible','off');
904 end
905
906 % ===================================================================
907 %> @brief close GUI panel for this object
908 %>
909 % ===================================================================
910 function closePanel(me,varargin)
911 if isfield(me.handles,'root') && isgraphics(me.handles.root)
912 delete(me.handles.root);
913 end
914 if isfield(me.handles,'parent') && isgraphics(me.handles.parent,'figure')
915 delete(me.handles.parent)
916 end
917 me.cleanHandles();
918 me.isGUI = false;
919 end
920
921 % ===================================================================
922 %> @fn cleanHandles
923 %> @brief clean any handles
924 %>
925 %> @param
926 %> @return
927 % ===================================================================
928 function cleanHandles(me, ~)
929 if isprop(me,'handles')
930 me.handles = [];
931 end
932 if isprop(me,'h')
933 me.h = [];
934 end
935 fprintf('===>>> baseStimulus: Ran clean handles!!!\n')
936 me.isGUI = false;
937 end
938
939 % ===================================================================
940 %> @fn getP
941 %> @brief gets a property copy or original property
942 %>
943 %> When stimuli are run, their properties are copied, so e.g. angle
944 %> is copied to angleOut and this is used during the task. This
945 %> method checks if the copy is available and returns that, otherwise
946 %> return the original.
947 %>
948 %> @param name of property
949 %> @param range of property to return
950 %> @return value of property
951 % ===================================================================
952 function [value, name] = getP(me, name, range)
953 % [value, name] = getP(me, name, range)
954 if isprop(me, [name 'Out']) && ~isempty(me.([name 'Out']))
955 name = [name 'Out'];
956 value = me.(name);
957 if exist('range','var'); value = value(range); end
958 elseif isprop(me, name)
959 value = me.(name);
960 if exist('range','var'); value = value(range); end
961 else
962 if me.verbose;fprintf('Property %s doesn''t exist...\n',name);end
963 value = []; name = [];
964 end
965 end
966
967 % ===================================================================
968 %> @fn setP
969 %> @brief sets a property copy or original property
970 %>
971 %> When stimuli are run, their properties are copied, so e.g. angle
972 %> is copied to angleOut and this is used during the task. This
973 %> method checks if the copy is available and returns that, otherwise
974 %> return the original.
975 %>
976 %> @param name of property
977 %> @param range of property to return
978 %> @return value of property
979 % ===================================================================
980 function setP(me, name, value)
981 % setP(me, name, value)
982 if isprop(me,[name 'Out'])
983 me.([name 'Out']) = value;
984 elseif isprop(me, name)
985 me.(name) = value;
986 else
987 if me.verbose;fprintf('Property %s doesn''t exist...\n',name);end
988 end
989 end
990
991 % ===================================================================
992 %> @fn updateXY
993 %> @brief Update only position info, faster and doesn't reset image etc.
994 %>
995 %> @param x X position
996 %> @param y Y position
997 %> @param useDegrees where the input is in degrees (true) ot pixels (false)
998 % ===================================================================
999 function updateXY(me,x,y,useDegrees)
1000 % updateXY(me, x, y, useDegrees)
1001 if ~exist('useDegrees','var') || isempty(useDegrees); useDegrees = false; end
1002 if useDegrees
1003 if ~isempty(x); me.xFinal = me.sM.toPixels(x, 'x'); me.xFinalD = x; end
1004 if ~isempty(y); me.yFinal = me.sM.toPixels(y, 'y'); me.yFinalD = y; end
1005 else
1006 if ~isempty(x); me.xFinal = x; me.xFinalD = me.sM.toDegrees(x, 'x'); end
1007 if ~isempty(y); me.yFinal = y; me.yFinalD = me.sM.toDegrees(y, 'y'); end
1008 end
1009 if length(me.mvRect) == 4
1010 me.mvRect=CenterRectOnPointd(me.mvRect, me.xFinal, me.yFinal);
1011 end
1012 end
1013
1014 end %---END PUBLIC METHODS---%
1015
1016 %=======================================================================
1017 methods ( Static ) %----------STATIC METHODS
1018 %=======================================================================
1019
1020 % ===================================================================
1021 %> @brief degrees2radians
1022 %>
1023 % ===================================================================
1024 function r = d2r(degrees)
1025 % d2r(degrees)
1026 r=degrees*(pi/180);
1027 end
1028
1029 % ===================================================================
1030 %> @brief radians2degrees
1031 %>
1032 % ===================================================================
1033 function degrees = r2d(r)
1034 % r2d(radians)
1035 degrees=r*(180/pi);
1036 end
1037
1038 % ===================================================================
1039 %> @brief findDistance in X and Y coordinates
1040 %>
1041 % ===================================================================
1042 function distance = findDistance(x1, y1, x2, y2)
1043 % findDistance(x1, y1, x2, y2)
1044 distance=sqrt((x2 - x1)^2 + (y2 - y1)^2);
1045 end
1046
1047 % ===================================================================
1048 %> @brief updatePosition returns dX and dY given an angle and delta
1049 %>
1050 % ===================================================================
1051 function [dX, dY] = updatePosition(delta, angle)
1053 dX = delta .* cos(baseStimulus.d2r(angle));
1054 if length(dX)== 1 && abs(dX) < 1e-3; dX = 0; end
1055 dY = delta .* sin(baseStimulus.d2r(angle));
1056 if length(dY)==1 && abs(dY) < 1e-3; dY = 0; end
1057 end
1058
1059 end%---END STATIC METHODS---%
1060
1061 %=======================================================================
1062 methods ( Access = protected ) %-------PRIVATE (protected) METHODS-----%
1063 %=======================================================================
1064
1065 % ===================================================================
1067 %> @brief These are transient properties that specify actions during runtime
1068 % ===================================================================
1069 function addRuntimeProperties(me)
1070 if isempty(me.findprop('doFlash')); me.addprop('doFlash');end
1071 if isempty(me.findprop('doDots')); me.addprop('doDots');end
1072 if isempty(me.findprop('doMotion')); me.addprop('doMotion');end
1073 if isempty(me.findprop('doDrift')); me.addprop('doDrift');end
1074 if isempty(me.findprop('doAnimator')); me.addprop('doAnimator');end
1076 end
1077
1078 % ===================================================================
1080 %> @brief Update transient properties that specify actions during runtime
1081 % ===================================================================
1082 function updateRuntimeProperties(me)
1083 me.doDots = false;
1084 me.doMotion = false;
1085 me.doDrift = false;
1086 me.doFlash = false;
1087 me.doAnimator = false;
1088 [v,n] = getP(me,'tf');
1089 if ~isempty(n) && v > 0; me.doDrift = true; end
1090 [v,n] = getP(me,'speed');
1091 if ~isempty(n) && v > 0; me.doMotion = true; end
1092 if strcmpi(me.family,'dots'); me.doDots = true; end
1093 if strcmpi(me.type,'flash'); me.doFlash = true; end
1094 if ~isempty(me.animator) && isa(me.animator,'animationManager')
1095 me.doAnimator = true;
1096 end
1097 end
1098
1099 % ===================================================================
1100 %> @brief compute xFinal and yFinal (in pixels) taking startPosition,
1101 %> xPosition, yPosition and direction/angle into account
1102 %>
1103 % ===================================================================
1104 function computePosition(me)
1105 if me.mouseOverride && me.mouseValid
1106 me.xFinal = me.mouseX; me.yFinal = me.mouseY;
1107 else
1108 sP = getP(me, 'startPosition');
1109 if isprop(me,'direction')
1110 [dx, dy]=pol2cart(me.d2r(getP(me,'direction')), sP);
1111 else
1112 [dx, dy]=pol2cart(me.d2r(getP(me,'angle')), sP);
1113 end
1114 me.xFinal = me.xPositionOut + (dx * me.ppd) + me.sM.xCenter;
1115 me.yFinal = me.yPositionOut + (dy * me.ppd) + me.sM.yCenter;
1116 me.xFinalD = me.sM.toDegrees(me.xFinal,'x');
1117 me.yFinalD = me.sM.toDegrees(me.yFinal,'y');
1118 if me.verbose; fprintf('---> computePosition: %s X = %gpx | %gpx | %gdeg <> Y = %gpx | %gpx | %gdeg\n',me.fullName, me.xFinal, me.xPositionOut, dx, me.yFinal, me.yPositionOut, dy); end
1119 end
1121 end
1122
1123 % ===================================================================
1124 %> @fn setAnimationDelta
1125 %> setAnimationDelta for performance better not to use get methods for dX dY and
1126 %> delta during animation, so we have to cache these properties to private copies so that
1127 %> when we call the animate method, it uses the cached versions not the
1128 %> public versions. This method simply copies the properties to their cached
1129 %> equivalents.
1130 % ===================================================================
1131 function setAnimationDelta(me)
1132 me.delta_ = me.delta;
1133 me.dX_ = me.dX;
1134 me.dY_ = me.dY;
1135 end
1136
1137 % ===================================================================
1138 %> @fn setRect
1139 %> setRect makes the PsychRect based on the texture and screen
1140 %> values, you should call computePosition() first to get xFinal and
1141 %> yFinal.
1142 % ===================================================================
1143 function setRect(me)
1144 if isempty(me.texture); me.mvRect = [0 0 100 100]; return; end
1145 if isprop(me,'scale')
1146 me.dstRect = ScaleRect(Screen('Rect',me.texture(1)), me.scale, me.scale);
1147 else
1148 me.dstRect=Screen('Rect',me.texture(1));
1149 end
1150 if me.mouseOverride && me.mouseValid
1151 me.dstRect = CenterRectOnPointd(me.dstRect, me.mouseX, me.mouseY);
1152 else
1153 me.dstRect=CenterRectOnPointd(me.dstRect, me.xFinal, me.yFinal);
1154 end
1155 me.mvRect=me.dstRect;
1156 if me.isRect; me.szPx=RectWidth(me.mvRect); end
1157 if me.verbose
1158 fprintf('---> %s setRect = [%.2f %.2f %.2f %.2f] width = %.2f height = %.2f\n',...
1159 me.fullName, me.dstRect(1), me.dstRect(2),me.dstRect(3),me.dstRect(4),...
1160 RectWidth(me.dstRect),RectHeight(me.dstRect));
1161 end
1162 end
1163
1164 % ===================================================================
1165 %> @fn toStructure
1166 %> @brief Converts properties to a structure
1167 %>
1168 %> @param me this instance object
1169 %> @param tmp is whether to use the temporary or permanent properties
1170 %> @return out the structure
1171 % ===================================================================
1172 function out=toStructure(me,tmp)
1173 if ~exist('tmp','var')
1174 tmp = 0; %copy real properties, not temporary ones
1175 end
1176 fn = fieldnames(me);
1177 for j=1:length(fn)
1178 if tmp == 0
1179 out.(fn{j}) = me.(fn{j});
1180 else
1181 out.(fn{j}) = me.([fn{j} 'Out']);
1182 end
1183 end
1184 end
1185
1186 % ===================================================================
1187 %> @fn removeTmpProperties
1188 %> @brief Finds and removes dynamic properties
1189 %>
1190 %> @param me
1191 %> @return
1192 % ===================================================================
1193 function removeTmpProperties(me)
1194 allprops = properties(me);
1195 for i=1:numel(allprops)
1196 m = findprop(me, allprops{i});
1197 if isa(m,'meta.DynamicProperty')
1198 delete(m)
1199 end
1200 end
1201 me.xFinal = [];
1202 me.xFinalD = [];
1203 me.yFinal = [];
1204 me.yFinalD = [];
1205 me.szPx = [];
1206 me.szD = [];
1207 me.isSetup = false;
1208 end
1209
1210 % ===================================================================
1211 %> @fn Delete method
1212 %>
1213 %> @param me
1214 %> @return
1215 % ===================================================================
1216 function delete(me)
1217 if ~isempty(me.texture)
1218 for i = 1:length(me.texture)
1219 if Screen(me.texture, 'WindowKind')~=0 ;try Screen('Close',me.texture); end; end %#ok<*TRYNC>
1220 end
1221 end
1222 if isprop(me,'buffertex') && ~isempty(me.buffertex)
1223 if Screen(me.buffertex, 'WindowKind')~=0 ; try Screen('Close',me.buffertex); end; end
1224 end
1225
1226 if me.verbose; fprintf('--->>> Delete: %s\n',me.fullName); end
1227 end
1228
1229 end%---END PRIVATE METHODS---%
1230end
ANIMATIONMANAGER Provides per frame paths for stimuli We integrate dyn4j java physics engine for rigi...
Definition animationManager.m:29
baseStimulus is the superclass for all stimulus objects
Definition baseStimulus.m:3
Property delayTime
Definition baseStimulus.m:71
Property speed
Definition baseStimulus.m:63
function computePosition(in me)
compute xFinal and yFinal (in pixels) taking startPosition, xPosition, yPosition and direction/angle ...
Property mouseValid
is mouse position within screen co-ordinates?
Definition baseStimulus.m:187
Property yFinalD
Definition baseStimulus.m:121
Property delta_
delta cache
Definition baseStimulus.m:205
function getMousePosition(in me)
get mouse position we make sure this is only called once per animation tick to improve performance an...
Property sM
our screen manager
Definition baseStimulus.m:165
Property xFinalD
X and Y position in °
Definition baseStimulus.m:119
Property szPx
computed size in pixels
Definition baseStimulus.m:113
function setAnimationDelta(in me)
Property ppd
pixels per degree (normally inhereted from screenManager)
Definition baseStimulus.m:139
Property xFinal
Definition baseStimulus.m:94
function setDelayTime(in me, in time)
set delayTime
static function d2r(in degrees)
degrees2radians
function setRect(in me)
Property ignorePropertiesUIBase
Which properties to not draw in the UI panel.
Definition baseStimulus.m:229
Property isRect
Definition baseStimulus.m:130
function delete(in me)
@ readPanelUpdate
triggered when reading from a UI panel,
Definition baseStimulus.m:244
function resetTicks(in me)
reset the various tick counters for our stimulus
Property colour
Definition baseStimulus.m:50
virtual setup(in runObject)
ALL Children must implement these 5 methods!
function getP(in me, in name, in range)
gets a property copy or original property
function updateRuntimeProperties(in me)
Update transient properties that specify actions during runtime.
Property alpha
Alpha (opacity) [0-1], this gets combined with the RGB colour.
Definition baseStimulus.m:53
virtual animate(in runObject)
animate the stimulus, normally called after a draw
static function findDistance(in x1, in y1, in x2, in y2)
findDistance in X and Y coordinates
virtual draw(in runObject)
draw to the screen buffer, ready for flip()
Property handles
handles for the GUI
Definition baseStimulus.m:162
Property texture
Our texture pointer for texture-based stimuli.
Definition baseStimulus.m:159
function setOffTime(in me, in time)
set offTime
Property verbose
Do we log extra details to the command-line?
Definition baseStimulus.m:86
function makePanel(in me, in parent)
make a GUI properties panel for this object
Property isVisible
true or false, whether to draw() this object
Definition baseStimulus.m:77
Property yFinal
Definition baseStimulus.m:98
Property type
stimulus type
Definition baseStimulus.m:23
static function r2d(in r)
radians2degrees
Property animator
animation manager
Definition baseStimulus.m:168
Property startPosition
Definition baseStimulus.m:59
virtual update(in runObject)
function closePanel(in me, in varargin)
close GUI panel for this object
Property yPosition
Definition baseStimulus.m:42
Property screenVals
screen settings generated by sM on setup
Definition baseStimulus.m:171
Property isSetup
Definition baseStimulus.m:174
Property offTime
time to turn stimulus off, relative to stimulus onset
Definition baseStimulus.m:74
Property mvRect
Definition baseStimulus.m:102
Property angle
angle in degrees (0 - 360)
Definition baseStimulus.m:66
Property dY
X update which is computed from our speed and angle.
Definition baseStimulus.m:152
Property szD
computed size in °
Definition baseStimulus.m:116
static function updatePosition(in delta, in angle)
updatePosition returns dX and dY given an angle and delta
function removeTmpProperties(in me)
Finds and removes dynamic properties.
function run(in me, in benchmark, in runtime, in s, in forceScreen, in showVBL)
Run stimulus in a window to preview it.
function updateXY(in me, in x, in y, in useDegrees)
Update only position info, faster and doesn't reset image etc.
Property dX_
dX cache
Definition baseStimulus.m:208
virtual reset(in runObject)
Property mouseX
mouse X position
Definition baseStimulus.m:190
Property delta
What our per-frame motion delta is.
Definition baseStimulus.m:146
function hide(in me)
Method to set isVisible=false.
Property dstRect
initial screen rectangle position [LEFT TOP RIGHT BOTTOM]
Definition baseStimulus.m:184
Property family
the stimulus family (grating, dots etc.)
Definition baseStimulus.m:30
function addRuntimeProperties(in me)
These are transient properties that specify actions during runtime.
Property mouseY
mouse Y position
Definition baseStimulus.m:193
function show(in me)
Method to set isVisible=true.
Property dX
X update which is computed from our speed and angle.
Definition baseStimulus.m:149
Property tick
tick updates +1 on each call of draw (even if delay or off is true and no stimulus is drawn,...
Definition baseStimulus.m:133
Property mouseOverride
override X and Y position with mouse input? Useful for RF mapping
Definition baseStimulus.m:80
Property xPosition
Definition baseStimulus.m:38
Property dY_
dY cache
Definition baseStimulus.m:211
function toStructure(in me, in tmp)
Converts properties to a structure.
Show images or directories full of images.
Definition imageStimulus.m:12
function getFonts(in me)
set paths for object
Property fullName
The fullName is the object name combined with its uuid and class name.
Definition optickaCore.m:59
function setPaths(in me)
Sets properties from a structure or normal arguments pairs, ignores invalid or non-allowed properties...
Property paths
storage of various paths
Definition optickaCore.m:52
Property sansFont
sans font
Definition optickaCore.m:69
Property name
object name
Definition optickaCore.m:22
screenManager — manage opening and configuring the PTB screen
Definition screenManager.m:20

Constructor & Destructor Documentation

◆ baseStimulus()

function baseStimulus::baseStimulus ( in  varargin)

Class constructor.

Parameters
vararginare passed as a structure / cell of properties which is parsed.
Returns
instance of class.

Member Function Documentation

◆ addRuntimeProperties()

baseStimulus::addRuntimeProperties ( in  me)
protected

These are transient properties that specify actions during runtime.

◆ alpha()

function set baseStimulus::alpha ( in  me,
in  value 
)

alpha set method

◆ animate()

◆ cleanHandles()

baseStimulus::cleanHandles ( in  me,
in  ignoredArg 
)

clean any handles

Parameters

return

◆ closePanel()

function baseStimulus::closePanel ( in  me,
in  varargin 
)

close GUI panel for this object

◆ colour()

function set baseStimulus::colour ( in  me,
in  value 
)

colour set method Allow 1 (R=G=B) 3 (RGB) or 4 (RGBA) value colour

◆ computePosition()

function baseStimulus::computePosition ( in  me)
protected

compute xFinal and yFinal (in pixels) taking startPosition, xPosition, yPosition and direction/angle into account

◆ d2r()

static function baseStimulus::d2r ( in  degrees)
static

degrees2radians

◆ delete()

function baseStimulus::delete ( in  me)
protected

◆ delta()

function get baseStimulus::delta ( in  me)

delta Get method delta is the normalised number of pixels per frame to move a stimulus

◆ draw()

◆ dX()

function get baseStimulus::dX ( in  me)

dX Get method X position increment for a given delta and angle

◆ dY()

function get baseStimulus::dY ( in  me)

dY Get method Y position increment for a given delta and angle

◆ findDistance()

static function baseStimulus::findDistance ( in  x1,
in  y1,
in  x2,
in  y2 
)
static

findDistance in X and Y coordinates

◆ getMousePosition()

function baseStimulus::getMousePosition ( in  me)

get mouse position we make sure this is only called once per animation tick to improve performance and ensure all stimuli that are following mouse position have consistent X and Y per frame update This sets mouseX and mouseY and mouseValid if mouse is within PTB screen (useful for mouse override positioning for stimuli)

◆ getP()

baseStimulus::getP ( in  me,
in  name,
in  range 
)

gets a property copy or original property

When stimuli are run, their properties are copied, so e.g. angle is copied to angleOut and this is used during the task. This method checks if the copy is available and returns that, otherwise return the original.

Parameters
nameof property
rangeof property to return
Returns
value of property

◆ hide()

function baseStimulus::hide ( in  me)

Method to set isVisible=false.

◆ hidePanel()

function baseStimulus::hidePanel ( in  me)

hide GUI properties panel for this object

◆ makePanel()

function baseStimulus::makePanel ( in  me,
in  parent 
)

make a GUI properties panel for this object

◆ r2d()

static function baseStimulus::r2d ( in  r)
static

radians2degrees

◆ readPanel()

function baseStimulus::readPanel ( in  me,
in  varargin 
)

read values from a GUI properties panel for this object

◆ removeTmpProperties()

baseStimulus::removeTmpProperties ( in  me)
protected

Finds and removes dynamic properties.

Parameters
me
Returns

◆ reset()

◆ resetTicks()

function baseStimulus::resetTicks ( in  me)

reset the various tick counters for our stimulus

◆ run()

baseStimulus::run ( in  me,
in  benchmark,
in  runtime,
in  s,
in  forceScreen,
in  showVBL 
)

Run stimulus in a window to preview it.

Parameters
benchmarktrue|false [optional, default = false]
runtimetime to show stimulus [optional, default = 2]
screenManagerto use [optional]
forceScreenfor a particulr monitor/screen to use
showVBLshow a plot of the VBL times

◆ selectFilePanel()

function baseStimulus::selectFilePanel ( in  me,
in  varargin 
)

read values from a GUI properties panel for this object

◆ setAnimationDelta()

baseStimulus::setAnimationDelta ( in  me)
protected

setAnimationDelta for performance better not to use get methods for dX dY and delta during animation, so we have to cache these properties to private copies so that when we call the animate method, it uses the cached versions not the public versions. This method simply copies the properties to their cached equivalents.

◆ setDelayTime()

function baseStimulus::setDelayTime ( in  me,
in  time 
)

set delayTime

◆ setOffTime()

function baseStimulus::setOffTime ( in  me,
in  time 
)

set offTime

◆ setP()

baseStimulus::setP ( in  me,
in  name,
in  value 
)

sets a property copy or original property

When stimuli are run, their properties are copied, so e.g. angle is copied to angleOut and this is used during the task. This method checks if the copy is available and returns that, otherwise return the original.

Parameters
nameof property
rangeof property to return
Returns
value of property

◆ setRect()

baseStimulus::setRect ( in  me)
protected

setRect makes the PsychRect based on the texture and screen values, you should call computePosition() first to get xFinal and yFinal.

◆ setup()

virtual baseStimulus::setup ( in  runObject)
virtual

ALL Children must implement these 5 methods!

initialise the stimulus with the PTB screenManager

Reimplemented in plaidStimulus.

◆ show()

function baseStimulus::show ( in  me)

Method to set isVisible=true.

◆ showPanel()

function baseStimulus::showPanel ( in  me)

show GUI properties panel for this object

◆ toStructure()

baseStimulus::toStructure ( in  me,
in  tmp 
)
protected

Converts properties to a structure.

Parameters
methis instance object
tmpis whether to use the temporary or permanent properties
Returns
out the structure

◆ update()

◆ updatePosition()

static function baseStimulus::updatePosition ( in  delta,
in  angle 
)
static

updatePosition returns dX and dY given an angle and delta

◆ updateRuntimeProperties()

baseStimulus::updateRuntimeProperties ( in  me)
protected

Update transient properties that specify actions during runtime.

◆ updateXY()

baseStimulus::updateXY ( in  me,
in  x,
in  y,
in  useDegrees 
)

Update only position info, faster and doesn't reset image etc.

Parameters
xX position
yY position
useDegreeswhere the input is in degrees (true) ot pixels (false)

Member Data Documentation

◆ alpha

Property baseStimulus::alpha

Alpha (opacity) [0-1], this gets combined with the RGB colour.

◆ angle

Property baseStimulus::angle

angle in degrees (0 - 360)

◆ animator

Property baseStimulus::animator
protected

animation manager

◆ colour

Property baseStimulus::colour

Colour as a 0-1 range RGB or RGBA vector (if you pass A it also modifies alpha and visa-versa

◆ delayTicks

Property baseStimulus::delayTicks
protected

delay ticks to wait until display

◆ delayTime

Property baseStimulus::delayTime

delay time to display relative to stimulus onset, can set upper and lower range for random interval. This allows for a group of stimuli some to be delayed relative to others for a global stimulus onset time.

◆ delta

Property baseStimulus::delta

What our per-frame motion delta is.

◆ delta_

Property baseStimulus::delta_
protected

delta cache

◆ drawTick

Property baseStimulus::drawTick

draw tick only updates when a draw is actually performed, resets on each update

◆ dstRect

Property baseStimulus::dstRect
protected

initial screen rectangle position [LEFT TOP RIGHT BOTTOM]

◆ dX

Property baseStimulus::dX

X update which is computed from our speed and angle.

◆ dX_

Property baseStimulus::dX_
protected

dX cache

◆ dY

Property baseStimulus::dY

X update which is computed from our speed and angle.

◆ dY_

Property baseStimulus::dY_
protected

dY cache

◆ family

Property baseStimulus::family
protected

the stimulus family (grating, dots etc.)

◆ handles

Property baseStimulus::handles
protected

handles for the GUI

◆ ignorePropertiesBase

Property baseStimulus::ignorePropertiesBase
protected

Which properties to ignore cloning when making transient copies in setup.

◆ ignorePropertiesUIBase

Property baseStimulus::ignorePropertiesUIBase
protected

Which properties to not draw in the UI panel.

◆ inSetup

Property baseStimulus::inSetup
protected

are we setting up?

◆ isGUI

Property baseStimulus::isGUI
protected

is panel constructed?

◆ isInSetColour

Property baseStimulus::isInSetColour
protected

deal with interaction of colour and alpha

◆ isRect

Property baseStimulus::isRect

is PTB stimulus type position defined via rect [true] or point [false] mvRect is the property used for rect based stimuli xFinal and yFinal are used for point-based positioninng

◆ isSetup

Property baseStimulus::isSetup
protected

◆ isVisible

Property baseStimulus::isVisible

true or false, whether to draw() this object

◆ mouseOverride

Property baseStimulus::mouseOverride

override X and Y position with mouse input? Useful for RF mapping

◆ mouseValid

Property baseStimulus::mouseValid
protected

is mouse position within screen co-ordinates?

◆ mouseX

Property baseStimulus::mouseX
protected

mouse X position

◆ mouseY

Property baseStimulus::mouseY
protected

mouse Y position

◆ mvRect

Property baseStimulus::mvRect

current screen rectangle position [LEFT TOP RIGHT BOTTOM] in pixels

◆ offTicks

Property baseStimulus::offTicks
protected

ticks before stimulus turns off

◆ offTime

Property baseStimulus::offTime

time to turn stimulus off, relative to stimulus onset

◆ ppd

Property baseStimulus::ppd

pixels per degree (normally inhereted from screenManager)

◆ screenVals

Property baseStimulus::screenVals
protected

screen settings generated by sM on setup

◆ setLoop

Property baseStimulus::setLoop
protected

◆ showOnTracker

Property baseStimulus::showOnTracker

show the position on the Eyetracker display?

◆ size

Property baseStimulus::size

Size in visual degrees (°), can also be used to scale images/movies or define width+height of a bar etc.

◆ sM

Property baseStimulus::sM
protected

our screen manager

◆ speed

Property baseStimulus::speed

speed in °/s - this mostly afffects linear motion, but with an animationManager is also used to define initial motion value

◆ startPosition

Property baseStimulus::startPosition

For moving stimuli do we start "before" our initial XY position? This allows you to center a stimulus at a screen location, but then drift it across that location, so if xyPosition is 0,0 and startPosition is -2 then the stimulus will start at -2 drifing towards 0.

◆ szD

Property baseStimulus::szD

computed size in °

◆ szIsPx

Property baseStimulus::szIsPx

whether sizeOut is degrees or pixels, see .szPx .szD for copies in pixels and degrees respectively

◆ szPx

Property baseStimulus::szPx

computed size in pixels

◆ texture

Property baseStimulus::texture
protected

Our texture pointer for texture-based stimuli.

◆ tick

Property baseStimulus::tick

tick updates +1 on each call of draw (even if delay or off is true and no stimulus is drawn, resets on each update

◆ type

Property baseStimulus::type

stimulus type

◆ verbose

Property baseStimulus::verbose

Do we log extra details to the command-line?

◆ xFinal

Property baseStimulus::xFinal

computed X position in pixel coordinates PTB uses: 0,0 top-left see computePosition(); a copy in degrees is made in xFinalD

◆ xFinalD

Property baseStimulus::xFinalD

X and Y position in °

◆ xPosition

Property baseStimulus::xPosition

initial X Position ± visual degrees (°) relative to screen center (0,0) in opticka +X is from left-to-right

◆ yFinal

Property baseStimulus::yFinal

computed Y position in pixel coordinates PTB uses: 0,0 top-left see computePosition(); ; a copy in degrees is made in yFinalD

◆ yFinalD

Property baseStimulus::yFinalD

◆ yPosition

Property baseStimulus::yPosition

initial Y Position ± visual degrees (°) relative to screen center (0,0) in opticka +Y is from top-to-bottom


The documentation for this class was generated from the following file: