Creative Commons License R.Muralikrishnan, MPI for Empirical Aesthetics. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Licence.
##############################################################################
##                                                                          ##
## NEO-Questionnaire - Neuroticism, Extraversion, Openness, Agreeableness & ##
##                 Conscientiousness with Radio Button Ratings              ##
##                                                                          ##
##             Experiment Script for use with Presentation                  ##
##                       Author: R. Muralikrishnan                          ##
##                                                                          ##
##############################################################################

##############################################################################
# Scenario Description Language (SDL) Header Part
##############################################################################

# These button codes have to correspond to those set in 'Settings -> Response'
active_buttons = 2;      # There are 3 active buttons defined in 'Settings -> Response'
button_codes = 1,2;    # These are the codes of those buttons

response_matching = simple_matching;  # Enables features not in legacy_matching

# Only those button presses that one expects are logged; not all
response_logging = log_active;

### NO EEG Triggers

# Default Settings for Font, FG and BG Colours etc.
default_background_color = "232, 240, 247"; # E8 F0 F7  # An off-bluish background  # RGB codes in decimal; 000 => Black
default_font = "Verdana";
default_font_size = 24;
default_text_color = "255, 255, 255"; # White
default_text_align = align_center;

default_deltat = 0;
default_picture_duration = next_picture; /* This implies that all pictures ...
/...are shown until the next picture is shown, unless otherwise specified */

#default_all_responses = false;

#Yoga 2 Tablet: 1920 x 1200

# Blues

# 3F 7E BC      63, 126, 188 Font Colour on Highlight
# 63 97 CB      99, 151, 203
# 9C BD DE     156, 189, 222 Default Button Colour
# C2 D7 EB     194, 215, 235
# D5 E3 F1     213, 227, 241

# E8 F0 F7     232, 240, 247 Default Background Colour

# 00 66 99     000, 102, 153  # An off-bluish tint

# Green
# ED FA CF        237, 250, 207
# 13 88 08         19, 136, 8   India Green
# 98 CF 2D

# Deep Saffron
# F4 C4 30       255, 153, 51

# FF CC 00

##############################################################################
# Scenario Description Language (SDL) Part
##############################################################################

begin;

# ============================
# SDL Variable Declarations: -
# ============================

# ==============================
# Picture Stimuli Definitions: - Everything that is shown, including text!
# ==============================

line_graphic {
   coordinates = -600, -72, -600, 71;
   coordinates = 600, -72, 600, 71;
   coordinates = -600, -70, 600, -70;
   coordinates = -600, 70, 600, 70;
   line_width = 4;
   line_color = 255, 255, 255;
} Lin_Border;

bitmap {filename = "Pointer-Arrow-Blue.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Pointer;  #232,240,247

ellipse_graphic { ellipse_width = 30; ellipse_height = 30; color = "232,240,247";} Gfx_Pointer;


array
{
	LOOP $i 20;
		text {caption = " "; background_color = "156,189,222"; width = 300; height = 70;};
	ENDLOOP;
} Txt_Array_Menu_Options;  # This constructs an SDL array of twenty Txt Picture Parts that can be dynamically added to Picture definitions.
                           # Declaring this inside the Picture definition doesn't work

array
{
	LOOP $i 20;
		text {caption = " "; font_color = "255,255,255"; background_color = "232,240,247"; width = 300; height = 70;};
	ENDLOOP;
} Txt_Array_Menu_Options_Placeholder;  # This constructs an SDL array of twenty Txt Picture Parts that can be dynamically added to Picture definitions.
                           # Declaring this inside the Picture definition doesn't work

array
{
	LOOP $i 20;
		box {color = "255,255, 255"; width = 304; height = 74;};
	ENDLOOP;
} Box_Array_Menu_Options;  # This constructs an SDL array of twenty Txt Picture Parts that can be dynamically added to Picture definitions.
                           # Declaring this inside the Picture definition doesn't work

array
{
	LOOP $i 20;
		box {color = "255,255, 255"; width = 304; height = 74;};
	ENDLOOP;
} Box_Array_Menu_Options_Placeholder;  # This constructs an SDL array of twenty Txt Picture Parts that can be dynamically added to Picture definitions.
                           # Declaring this inside the Picture definition doesn't work


bitmap {filename = "Next1.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Continue;
bitmap {filename = "Reconsider1.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Replay;
#bitmap {filename = "go-next.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Play;
#bitmap {filename = "go-next.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Pause;
#bitmap {filename = "go-next.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Forwards;
#bitmap {filename = "go-next.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Backwards;

bitmap {filename = "Speaker3.png"; transparent_color = "0,0,0"; scale_factor = 1;} Bmp_Audio_Playing;




array
{
	LOOP $i 100;
		ellipse_graphic { ellipse_width = 30; ellipse_height = 30; color = 255, 255, 255;};   # IMPORTANT: Ensure that the ellipse width and height specified here are greater than the
	ENDLOOP;                                                                                 #            values supplied as parameters for the get_rgb_pixel_color method below.  Otherwise it
} Gfx_Array_Radio_Buttons;                                                                  #            would break the code, because we'd be checking pixels that don't exist!!!


array
{
	LOOP $i 20;
			text {caption = " "; font_color = "63,126,188"; font_size = 18;};
	ENDLOOP;
} Txt_Array_Radio_Button_Left_Labels;  # This constructs an SDL array of twenty Txt Picture Parts that can be dynamically added to Picture definitions.
                                       # Declaring this inside the Picture definition doesn't work
                                       # Nesting of loops seems to be okay, but in PCL, we couldn't access Txt_x[x][y].  Apparently, only a single dimension array encompassing everything is created in PCL.
array
{
	LOOP $i 20;
			text {caption = " "; font_color = "63,126,188"; font_size = 18;};
	ENDLOOP;
} Txt_Array_Radio_Button_Right_Labels;


### ADDED for NEO Questionnaire
# To put labels on top of each radio button (i.e., in every column)
array
{
	LOOP $i 20;
			text {caption = " "; font_color = "63,126,188"; font_size = 18; formatted_text = true; };
	ENDLOOP;
} Txt_Array_Radio_Button_Top_Labels;

### ADDED for NEO Questionnaire
# To show a graphical legend

box {color = "255,255,255"; width = 1628; height = 38;} Box_Progress_Bar_Border;

box {color = "156,189,222"; width = 4; height = 30;} Box_Progress_Bar;

box {color = "255,255,255"; width = 1628; height = 4;} Box_Header_Line;


text {caption = " "; font_color = "63,126,188"; text_align = align_left;} Txt_Temp;

array
{
	LOOP $i 20;
		text {caption = " "; font = "Palatino Linotype"; font_color = "63,126,188"; text_align = align_left; font_size = 20; max_text_width = 1200;};
	ENDLOOP;
} Txt_Array_Questionnaire_Texts;


text {caption = "Hello there!"; font_color = "63,126,188"; max_text_width = 1200;} Txt_Message;

text
{
   caption = " "; font = "Palatino Linotype"; font_color = "30,30,30"; font_size = 18;
   background_color = "255, 255, 255"; text_align = align_left;
   width = 900; height = 600; max_text_width = 890;
} Txt_Description;


picture
{

	# This empty definition is legal.  PCL Program adds text picture parts to this dynamically.

} P_User_Interface;

picture
{

} P_Message;

# Screen definition for the End_Thanks trial
picture
{
    text {caption = "Vielen Dank für Ihre Teilnahme. \n\nBitte geben Sie der Versuchsleitung ein Handzeichen, dass Sie fertig sind."; font_color = "63,126,188";};
    x = 0;
    y = 0;

    #line_graphic Lin_Border;
    #x = 0;
    #y = 0;
} P_End_Thanks;

####  Specific for presenting Auditory Stimuli   -------------------------------
# ============================
# Sound Stimuli Definitions: -
# ============================

sound
{
    wavefile
    {
        filename = "";        # PCL Program below fills the file name
      preload = false;
    } Wav_Auditory_Stimulus;
} S_Auditory_Stimulus;

####


#=====================
# Trial Definitions: -
#=====================
trial
{
    trial_duration = 1000;
    all_responses = false;

    stimulus_event
    {
        picture {};     # This is the default picture, which is nothing!
        code = "CLS";   # Comment this out to avoid seeing this in the logfile.
    };
} T_Blank_Screen;

# Definition of the Trial that acts as the main user interface, to show messages as well as to get user input.
trial
{

    stimulus_event
    {
        picture P_User_Interface;  # No event code, since this trial will be presented in an infinite loop, and the picture parts will keep changing dynamically.
    };

} T_User_Interface;

# Definition of the Trial that logs the menu choice selected by the user.
trial
{
	stimulus_event
	{
		nothing{};
		code = " ";    # PCL Program Below changes this dynamically to save user choice in the log file in a meaningful manner.

	} E_Log_Menu_Choice_Selected;
} T_Log_Menu_Choice_Selected;

# Definition of the Trial that logs the radio buttons selected by the user.
trial
{
	stimulus_event
	{
		nothing{};
		code = " ";    # PCL Program Below changes this dynamically to save user choice in the log file in a meaningful manner.

	} E_Log_Radio_Buttons_Selected;
} T_Log_Radio_Buttons_Selected;

# Definition of the Trial to show a message.
trial
{

	trial_duration = 500;


    stimulus_event
    {
        picture P_Message;     # This is the default picture, which is nothing!
        code = "Message";   # Comment this out to avoid seeing this in the logfile.
    };
} T_Message;

# Definition of the Trial to play the Auditory Stimulus
trial
{
    trial_duration = stimuli_length;
    all_responses = false;

    # For Paul's LEM study, the screen must be blank, so this is not applicable.  Default value for monitor_sounds is true,
    # ...which means that nothing else happens until the sound ends.
    #monitor_sounds = false;            # If false, then, any sound that was/has started playing when prior to/during this trial
                                       # would continue to be played even if this trial ends.
                                       # This means that, once this trial starts and the music starts playing, the control immediately
                                       # whatever is next.  In our case, the screen with multiple menu boxes shows up immediately.
                                       # However, no responses / button-clicks will be recordable until the sound ends...thanks to all_responses = false.
                                       # Which is what the behaviour that one wants here.

    stimulus_event
    {
        sound S_Auditory_Stimulus;
        code = "";                        # PCL Program sets Event code
    } E_Auditory_Stimulus;
} T_Auditory_Stimulus;

####

# Definition of the Trial to end the session
# Operator Controlled
trial
{
    trial_duration = forever;
	 trial_type = specific_response;
	 terminator_button = 2;
    stimulus_event
    {
        picture P_End_Thanks;
        code = "Damit endet die Studie. \n\n Vielen Dank für Ihre Teilnahme!";
    };
    picture P_End_Thanks;
} T_End_Thanks;

##############################################################################
# Presentation Control Language (PCL) Program Part
##############################################################################

begin_pcl;

# Global PCL-Variables
mouse Dev_Mouse = response_manager.get_mouse(1);
int V_Pointer_Position_X = Dev_Mouse.x();
int V_Pointer_Position_Y = Dev_Mouse.y();

int N_of_Responses = response_manager.total_response_count(1);

int N_of_Menubox_Columns;  # That is, number of options presented horizontally (separated on the x axis, but identical y axis).
int N_of_Menubox_Rows;     # That is, number of options presented vertically (separated on the y axis, but identical x axis).

int V_Origin_X = 0;
int V_Origin_Y = 0;

int V_Box_Width = 300;
int V_Box_Height = 60;
int V_Box_Gap = 30;

int V_Button_Width = 30;
int V_Button_Height = 30;
int V_Button_Gap = 45;

int V_L, V_R, V_T, V_B; # Left, Right, Top and Bottom Co-ordinates

int V_First_Box_Centre_X, V_First_Box_Centre_Y;   # The centre of the first menu box on screen, calculated taking into account the number of row and columns
#int V_First_Box_Left_X, V_First_Box_Top_Y;

int V_First_Button_Centre_X, V_First_Button_Centre_Y;  # The centre of the first radio button on screen, calculated taking into account the number of row and columns

array<string> A_Menu_Options[0];  # 1 D Array of Menu Options to show
array<int> A_Menu_Coordinates[0][2]; # 2 D Array of Coordinates of the Menu Options: N_of_Menu Options x 2
# i => Current Menubox Counter
# [i][1] = x coordinate (centre)
# [i][2] = y coordinate (centre)

string V_Menu_Title;
string V_Error_Message;

int V_Menu_Choice_Clicked = 0;
int V_Menu_Box_Hovered_Over = 0;
int V_Current_Box = 1;
string V_Menu_Choice_Clicked_Text;

int V_Supplementary_Menu_Choice_Clicked = 0;
#string V_Supplementary_Menu_Choice_Clicked;

int V_Last_Calculated_Centre_X;
int V_Last_Calculated_Centre_Y;
int V_Last_Created_Box;

int N_of_Menubox_Columns_Last_Row;
bool V_Last_Row_Non_Standard = false;

array<string> A_Radio_Button_Options[0][0];  # 2 D Array of point-scale extremes, such as {Agree, Disagree} or {Acceptable, Not Acceptable}.
# i => Row Number Counter
# [i][1] = Left Label (say Agree)
# [i][2] = Right Label (say Disagree)

array<int> A_Radio_Button_Coordinates[0][2]; # 2 D Array of Coordinates of the Radio Button Options for a given x-point-scale.
# i => Current Button Counter
# [i][1] = x coordinate (centre)
# [i][2] = y coordinate (centre)

int N_of_Radio_Button_Rows;
int N_of_Radio_Button_Columns;
int V_Current_Button = 1;
int V_Radio_Button_Clicked;
int V_Radio_Button_Hovered_Over = 0;

int V_Pointer_Part_Index;

array<int> A_Radio_Buttons_Selected[0][3];
# 2 D array of N_of_Radio_Button_Rows x 3
# i => Row Number Counter
# [i][1] == V_Button_Index_In_Current_Row ===> This is the one that the experiment will use ultimately.
# [i][2] == V_Button_Index_Absolute...that is the continuous button numbers we generated...V_Current_Button
# [i][3] == Previously Selected V_Button_Index_In_Current_Row ...
            # This is just for the sake of having a record of what was selected before, if we are interested in the first choice that participants made.
            # We don't use it to change attributes etc.

array<string> A_Questionnaire_Texts[0];
string V_Questionnaire_Texts; # We'll just include all the questionnaire texts on one line in a separate input file, get the line from the file, split it based on #, and save the elements in the array above to use later.


int V_Current_Row; # The row in which the current button is located.
int V_Button_Index_In_Current_Row;  # So this will always be 1 to N_of_columns for each row, unlike V_Current_Button, which is continuous...and equal to N_of_rows x N_co_columns.

rgb_color RGB_Current_Button_Colour;
#int V_R_Byte = RGB_Current_Button_Colour.red_byte();
#int V_G_Byte = RGB_Current_Button_Colour.green_byte();
#int V_B_Byte = RGB_Current_Button_Colour.blue_byte();      # !(V_R_Byte == 255 && V_G_Byte == 0 && V_B_Byte == 0)

rgb_color RGB_Default_Button_Colour = rgb_color(255,255,255,255);   # Default colour of radio buttons when not hovered over or clicked.
rgb_color RGB_Hovered_Button_Colour = rgb_color(19,136,8,255);   # Colour of radio buttons when hovered over, but not clicked.
rgb_color RGB_Clicked_Button_Colour = rgb_color(255,153,51,255);     # Colour of radio buttons when clicked.

rgb_color RGB_Default_Menu_Font_Colour = rgb_color(255,255,255,255);   # Default colour of menu box text when not hovered over or clicked.
rgb_color RGB_Hovered_Menu_Font_Colour = rgb_color(63,126,188,255);   # Default colour of menu box when not hovered over or clicked.

rgb_color RGB_Default_Menu_BG_Colour = rgb_color(156,189,222,255);   # Colour of menu box text background when hovered over and / or clicked.
rgb_color RGB_Hovered_Menu_BG_Colour = rgb_color(237,250,207,255);   # Colour of menu box when hovered over and / or clicked.

rgb_color RGB_Dimmed_Menu_BG_Colour = rgb_color(232,240,247,255); # Colour of menu box text background when dimmed (while providing supplementary menu choice, for instance).

# Fourth value in colour = Alpha; Alpha = 0 => Fully transparent; Maximum alpha 255 => Fully opaque.

bool V_Selection_Completed = true; # Flat to indicate whether at least one radio button per row has been selected.
int V_Original_Part_Count;
int V_New_Part_Count;
bool V_Present_Supplementary_Menu = true;   # Flag to indicate whether the menu boxes can be presented or not based on whether radio button selection is complete or not.

# We're going to use these variables for calculating the progress bar size in one of the subroutines below.
                      # So we already declare them here.
int N_of_Trials = 22;
int V_Current_Trial;

###################################################
# PCL Subroutines to accomplish various functions
###################################################

# Subroutine to construct menu boxes
# ==================================

sub int
	Q_Construct_Menu_Boxes
	begin


		if A_Menu_Options.count() > 0 then

			loop int V_Row = 0 until V_Row == N_of_Menubox_Rows begin

				loop int V_Column = 0 until V_Column == N_of_Menubox_Columns begin


					A_Menu_Coordinates[V_Current_Box][1] =  V_First_Box_Centre_X + (V_Box_Width + V_Box_Gap)*V_Column;  # x will different for different columns; for a given row, x will be identical.
					A_Menu_Coordinates[V_Current_Box][2] =  V_First_Box_Centre_Y - (V_Box_Height + V_Box_Gap)*V_Row;    # y will different for different rows; for a given column, y will be identical.

				   V_Last_Calculated_Centre_Y = A_Menu_Coordinates[V_Current_Box][2]; # Useful when a last row with a non-standard number of columns need to be generated in a second step.

		         Txt_Array_Menu_Options[V_Current_Box].set_caption(A_Menu_Options[V_Current_Box]);
		         Txt_Array_Menu_Options[V_Current_Box].redraw();

					P_User_Interface.add_part(Box_Array_Menu_Options[V_Current_Box], A_Menu_Coordinates[V_Current_Box][1], A_Menu_Coordinates[V_Current_Box][2]);
					P_User_Interface.add_part(Txt_Array_Menu_Options[V_Current_Box], A_Menu_Coordinates[V_Current_Box][1], A_Menu_Coordinates[V_Current_Box][2]);

					# If necessary, add images to the buttons
					if A_Menu_Options[V_Current_Box] == "Weiter" then
						P_User_Interface.add_part(Bmp_Continue, A_Menu_Coordinates[V_Current_Box][1]+V_Box_Width/2-30, A_Menu_Coordinates[V_Current_Box][2]);
					end;

					if A_Menu_Options[V_Current_Box] == "Ändern" then
						P_User_Interface.add_part(Bmp_Replay, A_Menu_Coordinates[V_Current_Box][1]-V_Box_Width/2+30, A_Menu_Coordinates[V_Current_Box][2]);
					end;


					V_Last_Created_Box = V_Current_Box; # Necessary to construct a non-standard row, if any.

					V_Current_Box = V_Current_Box + 1; # Note that this is a continuous counter, unlike V_Column / V_Row;
                                                  # It cannot be straightforwardly derived from either of them for a given run;
                                                  # Its ultimate value (i.e., at the end of the nested RowxColumn loops) would correspond to A_Menu_Options.count().


					V_Column = V_Column + 1;

				end;

				V_Row = V_Row + 1;

			end;

      end;

	return 0;

end;

# Subroutine to polling the mouse and detect menu choice
# ======================================================
sub int
	Q_Poll_Device_For_Menu_Choice
	begin

		# Start polling the device incessantly until we have a response
		loop N_of_Responses = response_manager.total_response_count(1) until false
		begin

			# Show the Menu Screen
			T_User_Interface.present();

         # Poll device and change pointer position accordingly
			Dev_Mouse.poll();
			V_Pointer_Position_X = Dev_Mouse.x();
			V_Pointer_Position_Y = Dev_Mouse.y();

			P_User_Interface.set_part_x(V_Pointer_Part_Index, V_Pointer_Position_X); # Alternativerly, the pointer's part number will be A_Menu_Options.count()*2+1 = (No.of.Txt + No.of.Box) + 1 => (No. of elements in Menu Options Array x 2) + 1
			P_User_Interface.set_part_y(V_Pointer_Part_Index, V_Pointer_Position_Y); # Because we added the pointer as the last part, just before entering this subroutine

         # Initialise/Reset the pointer to the default
			Bmp_Pointer.set_filename("Pointer-Arrow-Blue.png");   # Reset the pointer.  Resetting things anywhere else, either in an else case below or out of the loop below doesn't work.
			Bmp_Pointer.load();                                    # In all other cases, some or all of the correct behaviour is lost.  So we do it here.

			# Initialise/Reset the text attributes to the default values
			Txt_Array_Menu_Options[V_Menu_Box_Hovered_Over].set_font_color(RGB_Default_Menu_Font_Colour);
			Txt_Array_Menu_Options[V_Menu_Box_Hovered_Over].set_background_color(RGB_Default_Menu_BG_Colour);
			Txt_Array_Menu_Options[V_Menu_Box_Hovered_Over].redraw();

         # Calculate the left, right, bottom and top extremes, considering we are on a menu box
			V_L = V_Pointer_Position_X - V_Box_Width/2;
			V_R = V_Pointer_Position_X + V_Box_Width/2;
			V_B = V_Pointer_Position_Y - V_Box_Height/2;
			V_T = V_Pointer_Position_Y + V_Box_Height/2;

         # Keep check if we are hovering over one of the menu boxes
			loop V_Current_Box = 1  until V_Current_Box > A_Menu_Options.count() begin

				if (V_L <= A_Menu_Coordinates[V_Current_Box][1] &&
					 V_R >= A_Menu_Coordinates[V_Current_Box][1] &&
					 V_B <= A_Menu_Coordinates[V_Current_Box][2] &&
					 V_T >= A_Menu_Coordinates[V_Current_Box][2]) then

					# If so, change its attributes and the pointer
					Txt_Array_Menu_Options[V_Current_Box].set_font_color(RGB_Hovered_Menu_Font_Colour);
					Txt_Array_Menu_Options[V_Current_Box].set_background_color(RGB_Hovered_Menu_BG_Colour);
					Txt_Array_Menu_Options[V_Current_Box].redraw();

					Bmp_Pointer.set_filename("Pointer-Hand-Orange.png");
					Bmp_Pointer.load();

					# If there was a click response when inside the menubox borders, this means the user has chosen the option; return that as the result
					if (response_manager.total_response_count(1) > N_of_Responses) then

						V_Menu_Choice_Clicked = V_Current_Box;

						V_Selection_Completed = true;

						#E_Log_Menu_Choice_Selected.set_event_code("|Menu Choice| " + A_Menu_Options[V_Menu_Choice_Clicked] + " selected. |");
						#T_Log_Menu_Choice_Selected.present();

						return V_Menu_Choice_Clicked;

					else
						# It was just a case of hovering over the menubox, but not selecting it.  Store this information to restore attributes for the menubox later.
						V_Menu_Box_Hovered_Over = V_Current_Box;
					end;

				end;

				V_Current_Box = V_Current_Box + 1;

			end;

         # Update our record of the total number of responses.
			N_of_Responses = response_manager.total_response_count(1);   # This line solved the issue of selecting an option hovered over, after a click outside the buttons.

		end;



	return 0;
end;




# Subroutine to show the menu boxes and return the user choice
# ============================================================

sub int
	Q_Show_Menu_Boxes(array<string,1> AL_Input_Array)  # Note that we are not using pass-by reference;  That would have been array<string,1>& AL_Input_Array;
                                                                  # Other than that, there won't be much of a difference in the code here;
                                                                  # However, we are using pass-by values, because, when calling the function, we just need to supply the values;
                                                                  # No need to declare an array, pass that, and then do an explicit resize etc.
                                                                  # The less the experimenter needs to adapt things, the better.  So, pass-by values good for us here.
	begin

		A_Menu_Options.assign(AL_Input_Array); # Copy contents into the global array.
		A_Menu_Coordinates.resize(A_Menu_Options.count() * 2);  # Make place to save x,y coordinates for each option...therefore * 2.

		N_of_Menubox_Columns = 3; # We specify that there can be a maximum of 3 columns in a row; anything more, and there will be more rows.

		if N_of_Menubox_Columns > A_Menu_Options.count() then N_of_Menubox_Columns = A_Menu_Options.count(); end;  # Just in case there are only 2 or less options supplied, things should still work.

		N_of_Menubox_Rows = (A_Menu_Options.count() - 1)/N_of_Menubox_Columns + 1; # The number of rows will be based on whether there are more boxes to fit than on a single row (of n boxes);

		N_of_Menubox_Columns_Last_Row =  mod((A_Menu_Options.count() - (N_of_Menubox_Rows - 1)*N_of_Menubox_Columns), N_of_Menubox_Columns);

		V_Last_Row_Non_Standard = false;

		if (N_of_Menubox_Rows > 1 && N_of_Menubox_Columns_Last_Row != 0) then V_Last_Row_Non_Standard = true; end; # If we have more than one row, and the last row works out to be a non-standard one, then set a flat to that effect.

		V_First_Box_Centre_X = V_Origin_X + ((V_Origin_X - V_Box_Width/2 - V_Box_Gap/2)*(N_of_Menubox_Columns - 1)); # We use the centre as the anchor.
		V_First_Box_Centre_Y = V_Origin_Y + ((V_Origin_Y + V_Box_Height/2 + V_Box_Gap/2)*(N_of_Menubox_Rows - 1));

		#V_First_Box_Left_X = (V_Origin_X - V_Box_Width/2) + ((V_Origin_X - V_Box_Width/2 - V_Box_Gap/2)*(N_of_Menubox_Columns - 1));  # If we want to use the top-left corner as the anchor.
		#V_First_Box_Top_Y = (V_Origin_Y + V_Box_Height/2) + ((V_Origin_Y + V_Box_Height/2 + V_Box_Gap/2)*(N_of_Menubox_Rows - 1));

		if (V_Last_Row_Non_Standard == true) then  # We have more than one row, and the last row is having a non-standard number of columns;

			V_Current_Box = 1;
			N_of_Menubox_Rows = N_of_Menubox_Rows - 1;               # We have a non-standard row to construct, which we will do in a second step.  So now, it is one less.
			Q_Construct_Menu_Boxes();                         # Construct the rows except the one with a non-standard number of columns;

			# Tweak parameters such that the non-standard row can be constructed.

			V_Current_Box = V_Last_Created_Box + 1;                  # The current box is not going to be the first, but follows the last created one.
			N_of_Menubox_Rows = 1;                                   # When we are here, it is always only one (non-standard row) we need to construct.
			N_of_Menubox_Columns = N_of_Menubox_Columns_Last_Row;    # Depends on the value set for N_of_Menubox_Columns above
			V_First_Box_Centre_X = V_Origin_X + ((V_Origin_X - V_Box_Width/2 - V_Box_Gap/2)*(N_of_Menubox_Columns - 1)); # Newly calcuated displaced X; using the standard formula though.
			V_First_Box_Centre_Y = V_Last_Calculated_Centre_Y - (V_Box_Height + V_Box_Gap);   # V_Last_Calculated_Centre_Y stored in the previous run of Q_Construct_Menu_Boxes.
																														 # The standard formula doesn't work here though...because we need to displace the origin itself.
																														 # Changing the origin and using the formula would also not do, because in the standard formula, y is not changed if Nr=1. And here Nr=1, but not the first row.
			Q_Construct_Menu_Boxes();

		else  # We have one or more rows, all with a standard number of columns; the easy option...all boxes constructed in one go.

			V_Current_Box = 1;
			Q_Construct_Menu_Boxes();

		end;

      # Add the pointer to the screen
		P_User_Interface.add_part(Bmp_Pointer, 0,-400);
		V_Pointer_Part_Index = P_User_Interface.part_count(); # Since we added the pointer as the last part, the part_count will also be the index of the last part (pointer).

		# Initialise
		V_Menu_Box_Hovered_Over = 1;

		return Q_Poll_Device_For_Menu_Choice();

	return 0;

end;



# Subroutine to construct radio button rows
# =========================================

sub int
	Q_Construct_Radio_Buttons
	begin

		if A_Radio_Button_Options.count() > 0 then

			loop int V_Row = 0 until V_Row == N_of_Radio_Button_Rows begin

				loop int V_Column = 0 until V_Column == N_of_Radio_Button_Columns begin


					A_Radio_Button_Coordinates[V_Current_Button][1] =  V_First_Button_Centre_X + (V_Button_Width + V_Button_Gap)*V_Column;  # x will different for different columns; for a given row, x will be identical.
					A_Radio_Button_Coordinates[V_Current_Button][2] =  V_First_Button_Centre_Y - (V_Button_Height + V_Button_Gap)*V_Row;    # y will different for different rows; for a given column, y will be identical.

				   V_Last_Calculated_Centre_X = A_Radio_Button_Coordinates[V_Current_Button][1]; # Useful to put the label boxes on either side of the row of radio buttons.
				   V_Last_Calculated_Centre_Y = A_Radio_Button_Coordinates[V_Current_Button][2]; # Necessary to put buttons such as continue etc. below the row of radio buttons.

					P_User_Interface.add_part(Gfx_Array_Radio_Buttons[V_Current_Button], A_Radio_Button_Coordinates[V_Current_Button][1], A_Radio_Button_Coordinates[V_Current_Button][2]);
					#P_User_Interface.add_part(Txt_Array_Menu_Options[V_Current_Box], A_Menu_Coordinates[V_Current_Box][1], A_Menu_Coordinates[V_Current_Box][2]);


					#V_Last_Created_Box = V_Current_Box; # Necessary to construct a non-standard row, if any.

					V_Current_Button = V_Current_Button + 1; # Note that this is a continuous counter, unlike V_Column / V_Row;
                                                  # It cannot be straightforwardly derived from either of them for a given run;
                                                  # Its ultimate value (i.e., at the end of the nested RowxColumn loops) would correspond to N_of_Radio_Button_Rows x N_of_Radio_Button_Columns.


					V_Column = V_Column + 1;

				end;


				V_Row = V_Row + 1;
                        # SPECIFIC for Q-NEO
			/**** NO TEXT LABELS for NEO Questionnaire on each row

				# Add text labels for the current row of radio buttons (we do it after incrementing the row number, because the row number starts from 0).

			   Txt_Array_Radio_Button_Left_Labels[V_Row].set_caption(A_Radio_Button_Options[V_Row][1]);
			   Txt_Array_Radio_Button_Left_Labels[V_Row].set_formatted_text(true);
			   Txt_Array_Radio_Button_Left_Labels[V_Row].redraw();

				Txt_Array_Radio_Button_Right_Labels[V_Row].set_caption(A_Radio_Button_Options[V_Row][2]);
				Txt_Array_Radio_Button_Right_Labels[V_Row].set_formatted_text(true);
			   Txt_Array_Radio_Button_Right_Labels[V_Row].redraw();

			   #int V_Left_Label_X = V_First_Button_Centre_X - (V_Box_Width/2 + V_Box_Gap/2); # Default: Labels slightly apart from the buttons...good when there is no questionnaire text, but just a scale.
			   int V_Left_Label_X = V_First_Button_Centre_X - (V_Box_Width/3);  # We want the labels to be closer up to the buttons. Good when there's a text in front of the scale/button.
				int V_Left_Label_Y = V_Last_Calculated_Centre_Y;

				#int V_Right_Label_X = V_Last_Calculated_Centre_X + (V_Box_Width/2 + V_Box_Gap/2); # Default: Labels slightly apart from the buttons...good when there is no questionnaire text, but just a scale.
				int V_Right_Label_X = V_Last_Calculated_Centre_X + (V_Box_Width/3); # We want the labels to be closer up to the buttons. Good when there's a text in front of the scale/button.
				int V_Right_Label_Y = V_Last_Calculated_Centre_Y;

			   P_User_Interface.add_part(Txt_Array_Radio_Button_Left_Labels[V_Row], V_Left_Label_X, V_Left_Label_Y);
			   P_User_Interface.add_part(Txt_Array_Radio_Button_Right_Labels[V_Row], V_Right_Label_X, V_Right_Label_Y);

			   ****/

			# SPECIFIC for Q-NEO
	         # Instead, there's five labels right on top of the Radio Buttons, before the first row.  That's added here.
	         # If we're on row 1, we need to put a label on each of the column by calculating the coordinates
	         # using the variables V_First_Button_Centre_X, V_First_Button_Centre_X, V_Button_Wdith and V_Button_Gap
	         if V_Row == 1 then
					# First, construct an array with the labels we need on top of the first row...otherwise a loop won't be possible below.
					string V_Top_Labels = "SA A N Z SZ";
					array<string> A_Top_Labels[0];
               V_Top_Labels.split(" ", A_Top_Labels);

					int V_Top_Label_X;  # This will be calculated based on the width and gap variables below.
               int V_Top_Label_Y = V_First_Button_Centre_Y + 70;   # This remains the same for all the labels.]
               int V_Progress_Bar_Width;
               int V_Progress_Bar_X = 0;

					loop int V_Top_Label_Counter = 1 until V_Top_Label_Counter > A_Top_Labels.count() begin

						Txt_Array_Radio_Button_Top_Labels[V_Top_Label_Counter].set_caption("<b>" + A_Top_Labels[V_Top_Label_Counter] + "</b>");
						Txt_Array_Radio_Button_Top_Labels[V_Top_Label_Counter].redraw();

						V_Top_Label_X = V_First_Button_Centre_X + (V_Button_Width + V_Button_Gap)*(V_Top_Label_Counter - 1);

						P_User_Interface.add_part(Txt_Array_Radio_Button_Top_Labels[V_Top_Label_Counter], V_Top_Label_X, V_Top_Label_Y);

						V_Top_Label_Counter = V_Top_Label_Counter + 1;

					end;

					P_User_Interface.add_part(Box_Progress_Bar_Border,0,-470);

               # These values (-810, 1620) as well as the Box_Progress_Bar_Border widths are based on the placement of the questionnaire text below.
               # Change these when that needs to be changed.

               # We do the following, because in add_part we cannot supply left_x;

               V_Progress_Bar_Width = (1620 / N_of_Trials)*V_Current_Trial;  # Yes, this is the main experiment loop counter!!!

					V_Progress_Bar_X = -810 + V_Progress_Bar_Width/2;

					Box_Progress_Bar.set_width(V_Progress_Bar_Width);
					#Box_Progress_Bar.

					P_User_Interface.add_part(Box_Progress_Bar,V_Progress_Bar_X,-470);

					Txt_Message.set_formatted_text(true);
					Txt_Message.set_font_size(18);
					Txt_Message.set_max_text_width(1400);
					Txt_Message.set_caption("<b>SA</b> = starke Ablehnung    <b>A</b> = Ablehnung    <b>N</b> = neutral    <b>Z</b> = Zustimmung    <b>SZ</b> = starke Zustimmung");
					Txt_Message.redraw();
					P_User_Interface.add_part(Txt_Message,0,500);

					P_User_Interface.add_part(Box_Header_Line, 0, V_First_Button_Centre_Y+45);


				end;


            # SPECIFIC for Scenarios in which there must be a question for each row of radio buttons.
            # Add the text that should appear in front of each radio button row; this is essentially the question.

            Txt_Array_Questionnaire_Texts[V_Row].set_formatted_text(true);
				Txt_Array_Questionnaire_Texts[V_Row].set_caption(A_Questionnaire_Texts[V_Row]);
				Txt_Array_Questionnaire_Texts[V_Row].ALIGN_LEFT;
				Txt_Array_Questionnaire_Texts[V_Row].redraw();

				# Since text picture parts are created in Presentation with a width just as wide as the text that they contain,
				# having left_align set doesn't make a difference to have the questionnaire left-justified...for the simple reason that
				# the text part is as big as the text, ... and therefore, it is the placement of the text picture part that would
				# actually help.  And here, because we can't use left_x in the add_part method unlike when declaring a text part in SDL as part of a picture definition,
				# we have to tweak the origin X of the text part.  To do that, we actually take a left-most point from which the text must start, and
				# from that, we displace the X by just half the width of the text in the text part.  That way, regardless of whether we have
				# two words or 10 words in the questionnaire text, they will always appear to be left-justified...but in fact, their origin X (=centre)
				# were tweaked to accomplish this rather than the text_alignment itself.

				int V_Questionnaire_Text_X = -810 + int(Txt_Array_Questionnaire_Texts[V_Row].width())/2;

            # This value above (-810) is also used for the calculation of the placement of the progress bar!  See above.

				P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[V_Row], V_Questionnaire_Text_X, V_Last_Calculated_Centre_Y);



				#Txt_Array_Menu_Options[V_Current_Box].ALIGN_LEFT() .set_caption(A_Menu_Options[V_Current_Box]);
		      #   Txt_Array_Menu_Options[V_Current_Box].redraw();


			end;

      end;

	return 0;

end;

# Subroutine to polling the mouse and detect button choice
# ========================================================
# Calls menu box subroutines to construct menu boxes after button selection is complete

sub int
	Q_Poll_Device_For_Radio_Button_Choice
	begin

		A_Radio_Buttons_Selected.resize(0);
      A_Radio_Buttons_Selected.resize(A_Radio_Button_Options.count()*3);	# Because we're storing three details for each row of radio buttons.  1. V_Button_Index_In_Current_Row, 2. V_Current_Button, 3. Previously selected V_Button_Index_In_Current_Row.




		# Start polling the device incessantly until we have selections for all rows of radio buttons
		loop N_of_Responses = response_manager.total_response_count(1) until false
		begin


			# Show the Radio Buttons Screen
			T_User_Interface.present();

         # Poll device and change pointer position accordingly
			Dev_Mouse.poll();
			V_Pointer_Position_X = Dev_Mouse.x();
			V_Pointer_Position_Y = Dev_Mouse.y();


			P_User_Interface.set_part_x(V_Pointer_Part_Index, V_Pointer_Position_X); # The pointer's part number will be (No.of.Txt + No.of.Box) + 1 => (No. of elements in Menu Options Array x 2) + 1
			P_User_Interface.set_part_y(V_Pointer_Part_Index, V_Pointer_Position_Y); # Because we added the pointer as the last part, just before entering this subroutine


         # Initialise/Reset the pointer to the default
			Bmp_Pointer.set_filename("Pointer-Arrow-Blue.png");#("Pointer-Blue-Orange.png");   # Reset the pointer.  Resetting things anywhere else, either in an else case below or out of the loop below doesn't work.
			Bmp_Pointer.load();                                    # In all other cases, some or all of the correct behaviour is lost.  So we do it here.


	      RGB_Current_Button_Colour = Gfx_Array_Radio_Buttons[V_Radio_Button_Hovered_Over].get_rgb_pixel_color(25,25); # IMPORTANT: These values must be less than the ellipse_width and heigt defined above in Gfx_Array_Radio_Buttons.


         # Since we're dealing with radio buttons, we should let the user keep hovering over the options to possibly reconsider their choice;
         # In that case, the button clicked on previously should remain clicked...but the other buttons should show the default behaviour of
         # changing to the default colours if it is hovered over but not clicked.

         if RGB_Current_Button_Colour != RGB_Clicked_Button_Colour then
				# Initialise/Reset the button attributes to the default values
				Gfx_Array_Radio_Buttons[V_Radio_Button_Hovered_Over].set_color(RGB_Default_Button_Colour);
				Gfx_Array_Radio_Buttons[V_Radio_Button_Hovered_Over].redraw();
         end;


         # Calculate the left, right, bottom and top extremes, considering we are on a menu box
			V_L = V_Pointer_Position_X - V_Button_Width/2;
			V_R = V_Pointer_Position_X + V_Button_Width/2;
			V_B = V_Pointer_Position_Y - V_Button_Height/2;
			V_T = V_Pointer_Position_Y + V_Button_Height/2;


         # Keep checking if we are hovering over one of the radio button
			loop V_Current_Button = 1  until V_Current_Button > A_Radio_Button_Options.count()*N_of_Radio_Button_Columns begin

				if (V_L <= A_Radio_Button_Coordinates[V_Current_Button][1] &&
					 V_R >= A_Radio_Button_Coordinates[V_Current_Button][1] &&
					 V_B <= A_Radio_Button_Coordinates[V_Current_Button][2] &&
					 V_T >= A_Radio_Button_Coordinates[V_Current_Button][2]) then

					# If so, change its attributes and the pointer


					RGB_Current_Button_Colour = Gfx_Array_Radio_Buttons[V_Current_Button].get_rgb_pixel_color(25,25); # IMPORTANT: These values must be less than the ellipse_width and heigt defined above in Gfx_Array_Radio_Buttons.

	            if RGB_Current_Button_Colour != RGB_Clicked_Button_Colour then
						Gfx_Array_Radio_Buttons[V_Current_Button].set_color(RGB_Hovered_Button_Colour);
						Gfx_Array_Radio_Buttons[V_Current_Button].redraw();
					end;


					Bmp_Pointer.set_filename("Pointer-Hand-Orange.png");#("Pointer-Orange-Blue.png");
					Bmp_Pointer.load();

					# If there was a click response when inside the menubox borders, this means the user has chosen the option; return that as the result
					if (response_manager.total_response_count(1) > N_of_Responses) then

						V_Radio_Button_Clicked = V_Current_Button;

						V_Current_Row = ((V_Current_Button - 1)/N_of_Radio_Button_Columns) + 1; # The row in which the current button is located.

						V_Button_Index_In_Current_Row = V_Current_Button - (V_Current_Row - 1)*N_of_Radio_Button_Columns; # So this will always be 1 to N_of_columns for each row, unlike V_Current_Button, which is continuous...and equal to N_of_rows x N_co_columns.


                  # If a radio button was previously clicked, and it is on the same row as the current one that was just clicked, then clear the previous one.
					   if A_Radio_Buttons_Selected[V_Current_Row][2] != 0 then


							Gfx_Array_Radio_Buttons[A_Radio_Buttons_Selected[V_Current_Row][2]].set_color(RGB_Default_Button_Colour);
							Gfx_Array_Radio_Buttons[A_Radio_Buttons_Selected[V_Current_Row][2]].redraw();


                  end;

                  Gfx_Array_Radio_Buttons[V_Current_Button].set_color(RGB_Clicked_Button_Colour);#.set_color(255,0,0,120);
					   Gfx_Array_Radio_Buttons[V_Current_Button].redraw();

					   # Store the previously selected button...the one that we just cleared the attributes for; just for the record. We don't use it to change attributes etc.
					   A_Radio_Buttons_Selected[V_Current_Row][3] = A_Radio_Buttons_Selected[V_Current_Row][1];

					   A_Radio_Buttons_Selected[V_Current_Row][1] = V_Button_Index_In_Current_Row;   # The button number on a per row basis that that experimenter will use ultimately.
					   A_Radio_Buttons_Selected[V_Current_Row][2] = V_Current_Button;                # The absolute button number, useful for the code here.

					   # In effect, A_Radio_Buttons_Selected[V_Current_Row][2]  is equal to  (V_Current_Row-1)*N_of_Radio_Button_Columns + A_Radio_Buttons_Selected[V_Current_Row][1];



					else
						# It was just a case of hovering over the menubox, but not selecting it.  Store this information to restore attributes for the menubox later.
						V_Radio_Button_Hovered_Over = V_Current_Button;

						RGB_Current_Button_Colour = Gfx_Array_Radio_Buttons[V_Radio_Button_Hovered_Over].get_rgb_pixel_color(25,25); # IMPORTANT: These values must be less than the ellipse_width and heigt defined above in Gfx_Array_Radio_Buttons.

	               if RGB_Current_Button_Colour != RGB_Hovered_Button_Colour && RGB_Current_Button_Colour != RGB_Clicked_Button_Colour then  #  !((V_R_Byte == 255 && V_G_Byte == 153 && V_B_Byte == 0) || (V_R_Byte == 255 && V_G_Byte == 0 && V_B_Byte == 0)
							Gfx_Array_Radio_Buttons[V_Radio_Button_Hovered_Over].set_color(RGB_Default_Button_Colour);
							Gfx_Array_Radio_Buttons[V_Radio_Button_Hovered_Over].redraw();
		            end;

					end;

				end;

				V_Current_Button = V_Current_Button + 1;

			end;

         # Update our record of the total number of responses.
			N_of_Responses = response_manager.total_response_count(1);   # This line solved the issue of selecting an option hovered over, after a click outside the buttons.

	      V_Selection_Completed = true;                                         # This needs to be set here to true every run of the loop;
                                                                                    # It will be reset to false by the loop below, ...
                                                                                    # even if one of the rows of buttons hasn't been selected yet.


         loop V_Current_Row = 1 until V_Current_Row > N_of_Radio_Button_Rows
         begin

	         if A_Radio_Buttons_Selected[V_Current_Row][1] == 0 then    # This means that, there's at least one row of buttons from which a selection hasn't been made yet.

					V_Selection_Completed = false;                          # So reset the flag to false to reflect this reality.

				end;

				V_Current_Row = V_Current_Row + 1;
			end;

         if V_Selection_Completed then                                 # This means that, there's a selection made for each of the row.  So basically we can enable further actions,
                                                                       # ... but still providing the opportunity to reconsider selections.
            V_Origin_X = 0; # Reset Origin X, in case it was changed (for instance for displaying not just scales, but questions on the left).
            V_Origin_Y = -550; # Tweak the origin, such that the menuboxes we're going to create are below the radio button boxes.  We don't want them to be relative to the buttons, otherwise we could have used the last_created_button_y on the RHS.


            P_User_Interface.remove_part(V_Pointer_Part_Index);          # Remove the pointer that we created when creating the radio buttons; For another one will be created as part of menu boxes.
				V_Original_Part_Count = P_User_Interface.part_count();       # Store the Originally existing number of parts (excluding the pointer, now that that's been removed) for use later.

				if V_Present_Supplementary_Menu then # It is the first time we show the supplementary menu; so show the replay option.

					V_Supplementary_Menu_Choice_Clicked = Q_Show_Menu_Boxes({"Ändern", "Weiter"});
					#V_Supplementary_Menu_Choice_Clicked_Text = A_Menu_Options[V_Supplementary_Menu_Choice_Clicked];
					V_Present_Supplementary_Menu = false; # Reset the flag such that the next time, the supplementary menu won't allow to replay the stimulus.

				else # It is not the first time we're here; so only show the continue button.  The user can replay only once.

					V_Supplementary_Menu_Choice_Clicked = Q_Show_Menu_Boxes({"Weiter"});
					V_Supplementary_Menu_Choice_Clicked = 2;  # Since there was only one choice in the menu, we just overwrite the variable, just so that the code below would work without changes.

				end;

				V_Origin_Y = 0;           # The ALL IMPORTANT thing to do!!! Reset the origin to the original value.


            if V_Supplementary_Menu_Choice_Clicked == 1 then   # Participant wishes to reconsider their ratings; So the current radio button selections must be cleared, and another round of selections must be enabled.

	            V_Supplementary_Menu_Choice_Clicked = 0;        # Resetting the choice made, such that we won't land here automatically, i.e., unless the menu is presented anew and the same choice made again!!!

               V_New_Part_Count = P_User_Interface.part_count();

				   # Clear the first round of radio button selections; Also change the corresponding button attributes to the default.
				   loop V_Current_Row = 1 until V_Current_Row > N_of_Radio_Button_Rows begin
						V_Radio_Button_Clicked = A_Radio_Buttons_Selected[V_Current_Row][2];
						Gfx_Array_Radio_Buttons[V_Radio_Button_Clicked].set_color(RGB_Default_Button_Colour);
						Gfx_Array_Radio_Buttons[V_Radio_Button_Clicked].redraw();
						A_Radio_Buttons_Selected[V_Current_Row][1] = 0;
						A_Radio_Buttons_Selected[V_Current_Row][2] = 0;
						V_Current_Row = V_Current_Row + 1;
					end;

               # Remove the new picture parts (including the new pointer) created by the Q_Show_Menu_Boxes... function such that the screen looks like just after a new set of radio buttons is presented, but with the old set of buttons, of course.
		         loop V_New_Part_Count until V_New_Part_Count <= V_Original_Part_Count
               begin
						P_User_Interface.remove_part(V_New_Part_Count);
                  V_New_Part_Count = V_New_Part_Count - 1;
               end;

               V_Pointer_Part_Index = 0; # We've just now removed everything that the Q_Show_Menu_Boxes... function created...including the pointer.  So reset its index accordingly.

					# Add a new pointer to the screen
				   P_User_Interface.add_part(Bmp_Pointer, 0,-400);
					V_Pointer_Part_Index = P_User_Interface.part_count();  # Since we added the pointer as the last part, the part_count will also be the index of the last part (pointer).






            elseif  V_Supplementary_Menu_Choice_Clicked == 2 then

               P_User_Interface.clear();


               loop V_Current_Row = 1 until V_Current_Row > N_of_Radio_Button_Rows begin

	               E_Log_Radio_Buttons_Selected.set_event_code("|Radio Button| " + string(A_Radio_Buttons_Selected[V_Current_Row][1]) + " selected for " + A_Radio_Button_Options[V_Current_Row][1] + "..." + A_Radio_Button_Options[V_Current_Row][2] + ". |");
						T_Log_Radio_Buttons_Selected.present();

						V_Current_Row = V_Current_Row + 1;
					end;

					return 2;
            end;

			end;

		end;

	return 0;
end;






# Subroutine to show radio buttons and record the user choice
# ===========================================================


sub int
	Q_Show_Radio_Buttons(array<string,2> AL_Input_Array)  # Note that we are not using pass-by reference;  That would have been array<string,1>& AL_Input_Array;
                                                                  # Other than that, there won't be much of a difference in the code here;
                                                                  # However, we are using pass-by values, because, when calling the function, we just need to supply the values;
                                                                  # No need to declare an array, pass that, and then do an explicit resize etc.
                                                                  # The less the experimenter needs to adapt things, the better.  So, pass-by values good for us here.
	begin

	   N_of_Radio_Button_Rows = AL_Input_Array.count();
	   N_of_Radio_Button_Columns = 5;


		A_Radio_Button_Options.assign(AL_Input_Array); # Copy contents into the global array.
		A_Radio_Button_Coordinates.resize(A_Radio_Button_Options.count() * N_of_Radio_Button_Rows * N_of_Radio_Button_Columns * 2);  # Make place to save x,y coordinates for each point-scale and for each column within it...therefore N_of_Rows * N_of_Columns * 2.


		V_First_Button_Centre_X = V_Origin_X + ((V_Origin_X - V_Button_Width/2 - V_Button_Gap/2)*(N_of_Radio_Button_Columns - 1)); # We use the centre as the anchor.
		V_First_Button_Centre_Y = V_Origin_Y + ((V_Origin_Y + V_Button_Height/2 + V_Button_Gap/2)*(N_of_Radio_Button_Rows - 1));


			V_Current_Button = 1;
			Q_Construct_Radio_Buttons();


      # Add the pointer to the screen
		P_User_Interface.add_part(Bmp_Pointer, 0,-400);
		V_Pointer_Part_Index = P_User_Interface.part_count();  # Since we added the pointer as the last part, the part_count will also be the index of the last part (pointer).


		# Initialise
		V_Radio_Button_Hovered_Over = 1;

		Q_Poll_Device_For_Radio_Button_Choice();



	return 0;

end;


# Subroutine to show radio buttons and record the user choice -- Pass-By-Reference
# ===========================================================


sub int                                                                  # Different from the pass-by value version above.
	Q_Show_Radio_Buttons_PBR(array<string,2>& AL_Input_Array)  # This sub-routine uses PASS-BY-REFERENCE;  That's why the ampersand in array<string,2>& ...;
                                                                  # Other than that, there isn't be much of a difference in the code here from the pass-by-value version above;

	begin
                                                                     # Different from the pass-by value version above.
	   N_of_Radio_Button_Rows = AL_Input_Array.count()/2;  # Since the input 2D array has rating pairs, but the counter would still be the number of individual items, we divide by 2.
	   N_of_Radio_Button_Columns = 7;                      # Same difference 2 lines below.


		A_Radio_Button_Options.assign(AL_Input_Array); # Copy contents into the global array.  # ... Different from the pass-by value version above.
		A_Radio_Button_Coordinates.resize(A_Radio_Button_Options.count()/2 * N_of_Radio_Button_Rows * N_of_Radio_Button_Columns * 2);  # Make place to save x,y coordinates for each point-scale and for each column within it...therefore N_of_Rows * N_of_Columns * 2.


		V_First_Button_Centre_X = V_Origin_X + ((V_Origin_X - V_Button_Width/2 - V_Button_Gap/2)*(N_of_Radio_Button_Columns - 1)); # We use the centre as the anchor.
		V_First_Button_Centre_Y = V_Origin_Y + ((V_Origin_Y + V_Button_Height/2 + V_Button_Gap/2)*(N_of_Radio_Button_Rows - 1));


			V_Current_Button = 1;
			Q_Construct_Radio_Buttons();


      # Add the pointer to the screen
		P_User_Interface.add_part(Bmp_Pointer, 0,-400);
		V_Pointer_Part_Index = P_User_Interface.part_count();  # Since we added the pointer as the last part, the part_count will also be the index of the last part (pointer).


		# Initialise
		V_Radio_Button_Hovered_Over = 1;

		Q_Poll_Device_For_Radio_Button_Choice();



	return 0;

end;



# Subroutine to clear previous menu and button choices; Resizes arrays; Resets Txt and Gfx (SDL Array) Attributes to their default
# ================================================================================================================================

sub
	Q_Clear_Previous_Button_And_Menu_Choices
	begin

		V_Menu_Box_Hovered_Over = 0;

		A_Menu_Options.resize(0);
		A_Menu_Coordinates.resize(0);

		loop V_Current_Box = 1 until V_Current_Box > 20   # This should be equal to the number of Txt elements created in the SDL part above
		begin


			 Txt_Array_Menu_Options[V_Current_Box].set_font_color(RGB_Default_Menu_Font_Colour);
			 Txt_Array_Menu_Options[V_Current_Box].set_background_color(RGB_Default_Menu_BG_Colour);
			 Txt_Array_Menu_Options[V_Current_Box].redraw();

			V_Current_Box = V_Current_Box + 1;
		end;


		V_Radio_Button_Hovered_Over = 0;

		A_Radio_Button_Options.resize(0);
		A_Radio_Button_Coordinates.resize(0);
		A_Radio_Buttons_Selected.resize(0);

		V_Current_Button = N_of_Radio_Button_Rows * N_of_Radio_Button_Columns;

		loop V_Current_Button = 1 until V_Current_Button > 100   # This should be equal to the number of Gfx elements created in the SDL part above
		begin

			Gfx_Array_Radio_Buttons[V_Current_Button].set_color(RGB_Default_Button_Colour);
			Gfx_Array_Radio_Buttons[V_Current_Button].redraw();

			V_Current_Button = V_Current_Button + 1;
		end;



end;

# Subroutine to clear previous menu and button choices; Resizes arrays; Resets Txt and Gfx (SDL Array) Attributes to their default
# ================================================================================================================================

sub
	Q_Hide_Unselected_Menu_Choices
	begin

		P_User_Interface.clear();

		loop V_Current_Box = 1 until V_Current_Box > A_Menu_Options.count()   # This should be equal to the number of Txt elements created in the SDL part above
      begin

			P_User_Interface.add_part(Box_Array_Menu_Options_Placeholder[V_Current_Box], A_Menu_Coordinates[V_Current_Box][1], A_Menu_Coordinates[V_Current_Box][2]);

			Txt_Array_Menu_Options_Placeholder[V_Current_Box].set_caption(A_Menu_Options[V_Current_Box]);
			Txt_Array_Menu_Options_Placeholder[V_Current_Box].set_font_color(RGB_Default_Menu_Font_Colour);
			Txt_Array_Menu_Options_Placeholder[V_Current_Box].set_background_color(RGB_Dimmed_Menu_BG_Colour);

			if V_Current_Box == V_Menu_Choice_Clicked then
				Txt_Array_Menu_Options_Placeholder[V_Current_Box].set_font_color(RGB_Hovered_Menu_Font_Colour);
				Txt_Array_Menu_Options_Placeholder[V_Current_Box].set_background_color(RGB_Hovered_Menu_BG_Colour);
			end;

			Txt_Array_Menu_Options_Placeholder[V_Current_Box].redraw();

			P_User_Interface.add_part(Txt_Array_Menu_Options_Placeholder[V_Current_Box], A_Menu_Coordinates[V_Current_Box][1], A_Menu_Coordinates[V_Current_Box][2]);

			V_Current_Box = V_Current_Box + 1;

		end;




		/*

		Txt_Menu_Placeholder.set_caption(V_Menu_Choice_Clicked_Text);
		Txt_Menu_Placeholder.redraw();



		P_User_Interface.add_part(Box_Menu_Placeholder, A_Menu_Coordinates[V_Menu_Choice_Clicked][1], A_Menu_Coordinates[V_Menu_Choice_Clicked][2]);
		P_User_Interface.add_part(Txt_Menu_Placeholder, A_Menu_Coordinates[V_Menu_Choice_Clicked][1], A_Menu_Coordinates[V_Menu_Choice_Clicked][2]);
		*/

end;

###################################################
# Experiment Execution Begins Here!!!
###################################################

#int N_of_Trials = 22;                   # Number of Pages of Questionnaire texts per Session.
# We do this on top, before the subroutines for NEO.

input_file F_Questionnaire_Texts = new input_file;
F_Questionnaire_Texts.open("Session_List_NEO-Questionnaire.txt");

#### We read one questionnaire text at a time...line by line for NEO.
###V_Questionnaire_Texts = F_Questionnaire_Texts.get_line();
### We have all the questionnaire texts on a single line, each individual one separated by a # in the input.
### Split the input line into individual questionnaire texts and store the output in an array.
###V_Questionnaire_Texts.split("#",A_Questionnaire_Texts);

int V_Hash_Index;

#========================
# Main Experiment Loop: -
#========================

	Txt_Message.set_caption("Im zweiten Teil der Studie werden Sie insgesamt 240 Aussagen lesen, die sich zur Beschreibung Ihrer eigenen Person eignen könnten. Lesen Sie bitte jede der Aussagen aufmerksam durch und wählen Sie diejenige Antwortoption aus, die nach Ihrer Meinung am ehesten auf Sie zutrifft. Es gibt keine richtigen oder falschen Antworten. Bitte bearbeiten Sie den Fragebogen möglichst spontan und wahrheitsgemäß. \n\nKlicken Sie auf WEITER, um zu beginnen.");
	Txt_Message.redraw();
	P_User_Interface.add_part(Txt_Message, 0, 100);

   V_Origin_Y = -200;
	Q_Show_Menu_Boxes({"Weiter"});

   P_User_Interface.remove_part(P_User_Interface.part_count());
   P_User_Interface.clear();
   Q_Clear_Previous_Button_And_Menu_Choices();



#==========
# Loop 1: -
#==========
loop    /*** Begin Loop 1 for Trial (==Pages of Questions in NEO) ***/
   V_Current_Trial = 1  # We defined this above, as an exception for NEO!

until
  V_Current_Trial > N_of_Trials

begin

  A_Questionnaire_Texts.resize(0); # Initialise / empty the array from previous values
  A_Questionnaire_Texts.resize(11); # Resize it to contain exactly the number of questionnaire texts intended to be diplayed per page.


  loop int i = 1 until i > 11 begin;
    A_Questionnaire_Texts[i] = F_Questionnaire_Texts.get_line();
    i = i + 1;
  end;

	V_Origin_Y = 0;

   V_Origin_X = 125;  # Tweak the Origin X, so that we have space for the questionnaire text.

	# There are no labels displayed in each row for the SSES Questionnaire...and the corresponding part in Q_Construct_Radio_Buttons is commented out (see above).
	# Instead, there's two labels right on top of the Radio Buttons, before the first row.  That's added as part of the code in Q_Construct_Radio_Buttons.

	# Since the number of questions is determined by the number of array elements here, and since we don't want labels on each row for the SSES questionnaire,
	# We could simply have {" "," "} 15 times, that works...but that's not very nice for the logfile, ...
	# so we just use the question number as dummy left and right labels here.

   V_Present_Supplementary_Menu = true;
	Q_Show_Radio_Buttons({{"1","1"}, {"2","2"}, {"3","3"}, {"4","4"}, {"5","5"}, {"6","6"}, {"7","7"}, {"8","8"}, {"9","9"}, {"10","10"}, {"11","11"}});
	P_User_Interface.clear();
	Q_Clear_Previous_Button_And_Menu_Choices();

   V_Origin_X = 0;   # Reset the Origin X, just in case.

	#T_Blank_Screen.present();
	Q_Clear_Previous_Button_And_Menu_Choices();


	# Go to the Next Page
	V_Current_Trial = V_Current_Trial + 1;



#================
# End Main Loop 1
#================
end; /*** End Loop 1 for Trials ***/


# Close all the open files

F_Questionnaire_Texts.close();

# Finish off the session!!!
T_End_Thanks.present();