# -*- coding: utf-8 -*-
from .screen import screen, screen_width, screen_height, monitor_diagonal
import os
import pygame
import time as builtin_time
import numpy as np
import datetime
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
class Time():
"""
A class object to wait some time, get time, control time and such.
Its methods (functions) are:
- reset()
- control()
- wait()
- get()
See those for further informations.
Note that by default, there is already a Time class object called "time" (lowercase) that is initialized at neuropsydia's loading. For the sake of clarity, use this one (e.g., n.time.wait() ), especially for wait() and control() functions.
Parameters
----------
None
Returns
----------
None
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> myclock = n.Time()
>>> time_passed_since_myclock_creation = myclock.get()
>>> myclock.reset()
>>> time_passed_since_reset = myclock.get()
>>> n.close()
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
- time
"""
def __init__(self):
self.clock = builtin_time.clock()
self.pygame_clock = pygame.time.Clock()
def reset(self):
"""
Reset the clock of the Time object.
Parameters
----------
None
Returns
----------
None
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> time_passed_since_neuropsydia_loading = n.time.get()
>>> n.time.reset()
>>> time_passed_since_reset = n.time.get()
>>> n.close()
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
- time
"""
self.clock = builtin_time.clock()
self.pygame_clock = pygame.time.Clock()
def control(self, frequency=60):
"""
Control time. Must be placed in a while loop and, each time the program runs through it, checks if the time passed is less than a certain amount (the frequency, by default 60, so 1/60 seconds). If true, the program stops and wait what needed before continuing, so that each loop takes at least 1/frequency seconds to be complete.
Parameters
----------
frequency = int, optional
The minimum frequency you want the loop to run at
Returns
----------
None
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> while n.time.get() < 5:
>>> n.time.control()
>>> print(n.time.get())
>>> n.close()
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
- time
"""
self.pygame_clock.tick_busy_loop(frequency)
def get(self, reset=True):
"""
Get time since last initialisation / reset.
Parameters
----------
reset = bool, optional
Should the clock be reset after returning time?
Returns
----------
float
Time passed in milliseconds.
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> time_passed_since_neuropsydia_loading = n.time.get()
>>> n.time.reset()
>>> time_passed_since_reset = n.time.get()
>>> n.close()
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
- time
"""
t = (builtin_time.clock()-self.clock)*1000
if reset is True:
self.reset()
return(t)
def wait(self, time_to_wait, unit="ms", frequency=60, round_by_frame=True, skip=None):
"""
Wait some time.
Parameters
----------
time_to_wait = int
Time to wait
unit = str
"min" for minutes, "s" for seconds, "ms" for milliseconds, or "frame" for a certain amount of frames (depending on the frequency parameter)
frequency = int
should be a multiple of your monitor's refresh rate
round by frame = bool
should the waiting time be rounded to match an exact number of frame / refresh cycles? (e.g., on a 60Hz monitor, 95ms will be rounded to 100, because the monitor is refreshed every 16.6667ms)
skip = str
Shoud there be a key to skip the waiting. Default to None.
Returns
----------
float
Actual time waited in milliseconds
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> n.write("let's wait 500ms", round_by_frame = False)
>>> n.refresh()
>>> wait_time = n.time.wait(520)
>>> n.newpage("white")
>>> n.write("I waited for " + str(wait_time) + "ms")
>>> n.refresh()
>>> wait_time = n.time.wait(520, round_by_frame = True)
>>> n.newpage("white")
>>> n.write("I waited for " + str(wait_time) + "ms")
>>> n.refresh()
>>> n.time.wait(3, unit = "s")
>>> n.close()
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
- time
"""
t0 = builtin_time.clock()
if unit == "min":
time_to_wait = time_to_wait * 60
unit = "s"
if unit == "s":
time_to_wait = time_to_wait * 1000
unit = "ms"
if unit == "ms":
if round_by_frame is True:
time_to_wait = round(time_to_wait / (1/frequency*1000))
time_to_wait = round(time_to_wait * (1/frequency*1000))
if unit == "frame":
time_to_wait = time_to_wait * (1/frequency*1000)
if skip is None:
pygame.time.delay(time_to_wait) # In milliseconds
else:
response(allow=skip, time_max=time_to_wait)
return((builtin_time.clock()-t0)*1000)
def now(self):
"""
Returns current (absolute) date and time.
Parameters
----------
None
Returns
----------
datetime
Current date and time.
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> n.time.now()
>>> n.close()
Authors
----------
Dominique Makowski
Dependencies
----------
- datetime
"""
return(datetime.datetime.now())
# Initialize a Time() object.
time = Time()
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
[docs]def newpage(color_name="white", opacity=100, fade=False, fade_speed=60, fade_type="out", auto_refresh=True):
"""
Fill the background with a color.
Parameters
------------
color_name : str, tuple, optional
name of the color (see color() function), or an RGB tuple (e.g., (122,84,01)).
opacity : int, optional
opacity of the color (in percents).
fade : bool, optional
do you want a fade effect?
fade_speed : int, optional
frequency (speed) of the fading.
fade_type : str, optional
"out" or "in", fade out or fade in.
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> n.newpage("blue")
>>> n.refresh()
>>> n.time.wait(500)
>>> n.close()
Notes
----------
*Authors*
- Dominique Makowski (https://github.com/DominiqueMakowski)
*Dependencies*
- pygame
- time
"""
if color_name is not None:
if fade is False:
if opacity == 100:
try:
screen.fill(color(color_name))
except:
print("NEUROPSYDIA ERROR: newpage(): wrong argument")
else:
opacity = int(opacity * 255 / 100)
color_name = color(color_name) + (opacity,)
mask = pygame.Surface((screen_width, screen_height), pygame.SRCALPHA) # per-pixel alpha
mask.fill(color_name) # notice the alpha value in the color
screen.blit(mask, (0, 0))
if auto_refresh is True:
refresh()
if fade is True:
original_color_name = color_name
clock = pygame.time.Clock()
for i in range(0, 40, 1):
clock.tick_busy_loop(fade_speed)
if fade_type == "out":
color_name = color(original_color_name) + (i,)
else:
color_name = color(original_color_name) + (255-i, )
mask = pygame.Surface((screen_width, screen_height), pygame.SRCALPHA) # per-pixel alpha
mask.fill(color_name) # notice the alpha value in the color
screen.blit(mask, (0, 0))
refresh()
screen.fill(color(original_color_name))
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
[docs]def refresh():
"""
Refresh / flip the screen: actually display things on screen.
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> n.newpage("blue")
>>> n.refresh()
>>> n.time.wait(500)
>>> n.close()
Notes
----------
*Authors*
- Dominique Makowski (https://github.com/DominiqueMakowski)
*Dependencies*
- pygame
"""
pygame.display.flip()
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
keys = {
"normal":
{109: ',', 44: ';', 46: ':',47: '!', 97: 'q',
98: 'b', 99: 'c', 100: 'd', 101: 'e',
102: 'f', 103: 'g', 104: 'h', 105: 'i', 106: 'j',
107: 'k', 108: 'l', 59: 'm', 110: 'n', 111: 'o',
112: 'p', 113: 'a', 114: 'r', 115: 's', 116: 't',
117: 'u', 118: 'v', 119: 'z', 120: 'x', 121: 'y',
122: 'w', 57: 'ç', 56: '_', 55: 'è', 54: '-', 53: '(',
52: "_", 51: '_', 50:'é', 49: '&', 48: 'à', 32: 'SPACE',
13: "ENTER",276: "LEFT",274: "DOWN",275: "RIGHT",273: "UP",
266: ".",
pygame.K_KP0: '0', pygame.K_KP1: '1', pygame.K_KP2: '2', pygame.K_KP3: '3',pygame.K_KP4: '4', pygame.K_KP5: '5',pygame.K_KP6: '6',pygame.K_KP7: '7',pygame.K_KP8: '8',pygame.K_KP9: '9'},
"shift":
{109:'?', 44: '.', 46: '/',47: '§', 97: 'Q',
98: 'B', 99: 'C', 100: 'D', 101 : 'E',
102: 'F', 103: 'G', 104: 'H', 105: 'I', 106: 'J',
107: 'K', 108: 'L', 59: 'M', 110: 'N', 111: 'O',
112: 'P', 113: 'A', 114: 'R', 115: 'S', 116: 'T',
117: 'U', 118: 'V', 119: 'Z', 120: 'X', 121: 'Y',
122: 'W', 57: '9', 56: '8', 55: '7', 54: '6', 53: '5',
52: '4', 51: '3', 50: '2', 49: '1', 48: '0', 32: 'SPACE',
13: "ENTER",276: "LEFT",274: "DOWN",275: "RIGHT",273: "UP",
266: ".",
pygame.K_KP0: '0',pygame.K_KP1: '1',pygame.K_KP2: '2',pygame.K_KP3:'3',pygame.K_KP4: '4',
pygame.K_KP5: '5',pygame.K_KP6: '6',pygame.K_KP7: '7',pygame.K_KP8: '8',pygame.K_KP9:'9'},
"altgr":
{97: 'q', 98: 'b', 99: 'c', 100: 'd', 101 : '€',
102: 'f', 103: 'g', 104: 'h', 105: 'i', 106: 'j',
107: 'k', 108: 'l', 59: 'm', 110: 'n', 111: 'o',
112: 'p', 113: 'a', 114: 'r', 115: 's', 116: 't',
117: 'u', 118: 'v', 119: 'z', 120: 'x', 121: 'y',
122: 'w', 57: '^', 56: '_', 55: '`', 54: '|', 53: '[',
52: '{', 51: '#', 50: '~', 49: '1', 48: '@', 32: 'SPACE',
13: "ENTER",276: "LEFT",274: "DOWN",275: "RIGHT",273: "UP",
266: ".",
pygame.K_KP0: '0',pygame.K_KP1: '1',pygame.K_KP2: '2',pygame.K_KP3: '3',pygame.K_KP4: '4',
pygame.K_KP5: '5',pygame.K_KP6: '6',pygame.K_KP7: '7',pygame.K_KP8: '8',pygame.K_KP9: '9'}
}
def wait_for_input(time_max=None):
"""
Low level input checker.
Parameters
----------
time_max = int
time max in ms
Returns
----------
key
A key.
Example
----------
NA
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
- time
"""
if pygame.event.get_blocked(pygame.KEYDOWN) is True:
blocked = True
pygame.event.set_allowed(pygame.KEYDOWN)
else:
blocked = False
pygame.event.set_allowed(pygame.KEYDOWN)
time_out = False
loop = True
if time_max is None:
while loop:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if pygame.key.get_mods() & pygame.KMOD_SHIFT:
modifier = "shift"
elif pygame.key.get_mods() & pygame.KMOD_RALT:
modifier = "altgr"
else:
modifier = "normal"
if event.key != pygame.K_RSHIFT and event.key != pygame.K_LSHIFT and event.key != pygame.K_RALT:
loop = False
else:
local_time = Time()
while loop and local_time.get(reset=False) < time_max:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if pygame.key.get_mods() & pygame.KMOD_SHIFT:
modifier = "shift"
elif pygame.key.get_mods() & pygame.KMOD_RALT:
modifier = "altgr"
else:
modifier = "normal"
if event.key != pygame.K_RSHIFT and event.key != pygame.K_LSHIFT and event.key != pygame.K_RALT:
loop = False
if local_time.get(reset=False) > time_max:
time_out = True
if blocked is True:
pygame.event.set_blocked(pygame.KEYDOWN)
if time_out == True:
return("Time_Max_Exceeded")
else:
try:
return(keys[modifier][event.key])
except KeyError:
return(event.key)
[docs]def response(allow=None, enable_escape=True, time_max=None, get_RT=True):
"""
Get a (keyboard, for now) response.
Parameters
----------
allow : str or list
Keys to allow.
enable_escape : bool
Enable escape key to exit.
time_max : int
Maximum time to wait for a response (ms).
get_RT : bool
Return response time.
Returns
----------
str or tuple
returns a tuple when get_RT is set to True
Notes
----------
*Authors*
- Dominique Makowski (https://github.com/DominiqueMakowski)
*Dependencies*
- pygame
"""
local_time = Time()
if allow is not None:
if not isinstance(allow, list):
allow = [allow]
while True:
pressed_key = wait_for_input(time_max=time_max)
if pressed_key == "Time_Max_Exceeded":
return("Time_Max_Exceeded", local_time.get())
if pressed_key == pygame.K_ESCAPE:
if enable_escape is True:
if get_RT is True:
return("ESCAPE", local_time.get())
else:
return("ESCAPE")
elif allow is not None:
if pressed_key in allow:
if get_RT is True:
return(pressed_key, local_time.get())
else:
return(pressed_key)
else:
if get_RT is True:
return(pressed_key, local_time.get())
else:
return(pressed_key)
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
class Coordinates:
"""
A class object to go from pygame corrdinates system to neuropsydia's and vice versa.
Its methods (functions) are:
- to_pygame()
- from_pygame()
Parameters
----------
None
Returns
----------
None
Example
----------
None
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
"""
def to_pygame(x=None, y=None, distance_x=None, distance_y=None):
"""
Convert coordinates from neuropsydia (-10:10) to pygame's system (in pixels).
Parameters
----------
x = float
[-10:10]
y = float
[-10:10]
distance_x = convert a horizontal distance
[-10:10]
distance_y = convert a horizontal distance
[-10:10]
Returns
----------
NA
Example
----------
NA
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
"""
if x != None and y == None:
x = (x+10.0)/(10.0+10.0)*(screen_width-0.0)+0.0
return(int(x))
if x == None and y != None:
y = (-y+10.0)/(10.0+10.0)*(screen_height-0.0)+0.0
return(int(y))
if x != None and y != None:
x = (x+10.0)/(10.0+10.0)*(screen_width-0.0)+0.0
y = (-y+10.0)/(10.0+10.0)*(screen_height-0.0)+0.0
return(int(x),int(y))
if distance_x != None and distance_y is None:
distance_x = (distance_x)/(10.0+10.0)*(screen_width-0.0)+0.0
return(int(distance_x))
if distance_y != None and distance_x is None:
distance_y = (-distance_y)/(10.0+10.0)*(screen_height-0.0)+0.0
return(int(distance_y))
if distance_x != None and distance_y != None:
distance_x = (distance_x)/(10.0+10.0)*(screen_width-0.0)+0.0
distance_y = (-distance_y)/(10.0+10.0)*(screen_height-0.0)+0.0
return(int(distance_x), int(distance_y))
def from_pygame(x=None, y=None):
"""
Help incomplete, sorry.
Parameters
----------
NA
Returns
----------
NA
Example
----------
NA
Authors
----------
Dominique Makowski
Dependencies
----------
- pygame
"""
if x != None and y == None:
x =20*x/screen_width - 10
return(x)
if x == None and y != None:
y = -(20*y/screen_height) + 10
return(y)
if x != None and y != None:
x =20*x/screen_width - 10
y = -(20*y/screen_height) + 10
return(x, y)
def to_physical(distance_x=None, distance_y=None, monitor_diagnonal=monitor_diagonal, unit="cm"):
"""
Help incomplete, sorry.
Parameters
----------
monitor_diagonal = int
in inches (24, 27, etc).
Returns
----------
NA
Example
----------
NA
Authors
----------
Dominique Makowski
Dependencies
----------
None
"""
if unit=="cm":
diagonal = monitor_diagonal*2.54
coef = np.sqrt(((screen_height*screen_height) + (screen_width*screen_width))/(diagonal*diagonal))
monitor_height = screen_height/coef
monitor_width = screen_width/coef
if distance_x != None and distance_y is None:
distance_x = (distance_x)/(10.0+10.0)*(monitor_width-0.0)+0.0
return(int(distance_x))
if distance_y != None and distance_x is None:
distance_y = (distance_y)/(10.0+10.0)*(monitor_height-0.0)+0.0
return(int(distance_y))
if distance_y != None and distance_x != None:
distance_x = (distance_x)/(10.0+10.0)*(monitor_width-0.0)+0.0
distance_y = (distance_y)/(10.0+10.0)*(monitor_height-0.0)+0.0
return(distance_x, distance_y)
def from_physical(distance_x=None, distance_y=None, monitor_diagonal=monitor_diagonal, unit="cm"):
"""
Help incomplete, sorry.
Parameters
----------
monitor_diagonal = int
in inches (24, 27, etc).
Returns
----------
NA
Example
----------
NA
Authors
----------
Dominique Makowski
Dependencies
----------
None
"""
if unit=="cm":
diagonal = monitor_diagonal*2.54
coef = np.sqrt(((screen_height*screen_height) + (screen_width*screen_width))/(diagonal*diagonal))
monitor_height = screen_height/coef
monitor_width = screen_width/coef
if distance_x != None and distance_y is None:
distance_x = (distance_x)*(10.0+10.0)/(monitor_width-0.0)+0.0
return(int(distance_x))
if distance_y != None and distance_x is None:
distance_y = (distance_y)*(10.0+10.0)/(monitor_height-0.0)+0.0
return(int(distance_y))
if distance_y != None and distance_x != None:
distance_x = (distance_x)/(10.0+10.0)*(monitor_width-0.0)+0.0
distance_y = (distance_y)/(10.0+10.0)*(monitor_height-0.0)+0.0
return(distance_x, distance_y)
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
class Font_Cache_Init:
def __init__(self):
self.cache = {} #Initialize an empty cache
def get(self,font_path,size):
if not (font_path,int(size)) in self.cache: #if not in cache,
if os.path.exists(font_path): #if the path leads to a font,
self.cache[font_path,int(size)] = pygame.font.Font(font_path, int(size)) #load this font
else:
self.cache[font_path,int(size)] = pygame.font.SysFont(font_path, int(size)) #load a system font
return(self.cache[font_path,int(size)])
global Font
Font = Font_Cache_Init() #Create the font object that will update itself with the different loaded fonts
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
color_list = {
"white":(255,255,255),
"w":(255,255,255),
"black":(0,0,0),
"b":(0,0,0),
"grey":(128,128,128),
"g":(128,128,128),
"raw_red":(255,0,0),
"raw_green":(0,255,0 ),
"raw_blue":(0, 0, 255),
"red":(244,67,54),
"pink":(233,30,99),
"purple":(156,39,176),
"deeppurple":(103,58,183),
"indigo":(63,81,181),
"blue":(33,150,243),
"lightblue":(3,169,244),
"cyan":(0,188,212),
"teal":(0,150,136),
"green":(76,175,80),
"lightgreen":(139,195,74),
"lime":(205,220,57),
"yellow":(255,235,59),
"amber":(255,193,7),
"orange":(255,152,0),
"deeporange":(255,87,34),
"brown":(121,85,72),
"lightgrey":(220,220,220),
"darkgrey":(105,105,105),
"bluegrey":(96,125,139),
"pale_red":(239,154,154),
"pale_pink":(244,143,177),
"pale_purple":(206,147,216),
"pale_deeppurple":(179,157,219),
"pale_indigo":(159,168,218),
"pale_blue":(144,202,249),
"pale_light_blue":(129,212,250),
"pale_cyan":(128,222,234),
"pale_teal":(128,203,196),
"pale_green":(165,214,167),
"pale_lightgreen":(197,225,165),
"pale_lime":(230,238,156),
"pale_yellow":(255,245,157),
"pale_amber":(255,224,130),
"pale_orange":(255,204,128),
"pale_deeporange":(255,171,145),
"pale_brown":(188,170,164),
"blue_shade":[(204,229,255),(153,204,255),(102,178,222),(51,153,255),(0,128,255)],
"red_shade":[(255,204,204),(255,153,153),(255,102,102),(255,51,51),(255,0,0)],
"green_shade":[(204,255,204),(153,255,153),(102,255,102),(51,255,51),(0,255,0)],
"multi_shade":[(255,51,51),(255,51,255),(51,153,255),(51,255,51),(255,153,51)]
}
def color(color):
"""
Returns an RGB color tuple (or list) from its name.
Parameters
----------
color = str
one from the color_list list
Returns
----------
tuple or list
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> print(n.color_list)
>>> print(n.color("blue"))
>>> n.close()
Authors
----------
Dominique Makowski
Dependencies
----------
None
"""
if isinstance(color,str):
try:
return(color_list[color])
except:
print("NEUROPSYDIA WARNING: color() was used, however the argument " + str(color) + " was not detected and might cause errors.")
return(color)
else:
return(color)
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
# ==============================================================================
def cursor(visible=True):
"""
Set the mouse cursor to visible or invisible.
Parameters
----------
visible = bool
True for visible, False for invisible.
Returns
----------
None
Example
----------
>>> import neuropsydia as n
>>> n.start()
>>> n.cursor(True)
>>> n.time.wait(2000)
>>> n.close()
Authors
----------
The pygame team
Dependencies
----------
- pygame 1.9.2
"""
pygame.mouse.set_visible(visible)