Creative Commons License R.Muralikrishnan, MPI for Empirical Aesthetics. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Licence.
##############################################################################
##                                                                          ##
##    Know-2 : Auditory Study with Contextual Text and Music Presentation   ##
##                        with Radio Button Ratings                         ##
##    Each trial consists of one identical track followed by an             ##
##    extenstive rating. Just the preceding context text is different.      ##
##                                                                          ##
##             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 250;
		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 30;
			text {caption = " "; font = "Palatino Linotype Fett"; font_color = "63,126,188"; font_size = 18; formatted_text = true;};
	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 30;
			text {caption = " "; font = "Palatino Linotype Fett"; font_color = "63,126,188"; font_size = 18; formatted_text = true;};
	ENDLOOP;
} Txt_Array_Radio_Button_Right_Labels;

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

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


text {caption = "Hello there!"; font = "Palatino Linotype"; font_size = 20; font_color = "63,126,188";
      text_align = align_left; max_text_width = 1600;
      formatted_text = true;
} Txt_Message;

text
{
   caption = " ";
   font = "Palatino Linotype"; font_color = "36,36,36"; font_size = 20;
   text_align = align_left; max_text_width = 1250;
   formatted_text = true; transparent_color = "232,240,247";  # We sometimes have a box of a different colour as the background (see below)
} Txt_Description;                                            # In that case, we want the text part to be transparent (from the default background) such that the box colour comes through.

box
{
   color = "236,236,236"; # A bookish-pale-yellow #ECECEC
   height = 1000;
   width = 2400; # Well, yes it is beyond the monitor size...so we don't have to change it for different resolutions.
} Box_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."; 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;

####

# Screen definition for getting a text input from the participant keyboard
picture
{
   text { caption = "Test Test Test"; font = "Palatino Linotype"; font_color = "63,126,188"; max_text_width = 1200; font_size = 20; formatted_text = true;} Txt_Instruction1;
   x = 0;
   y = 120;

	box {color = "255,255,255"; width = 710; height = 310;} Box_Keyboard_Input; # Box First, Textfield next...otherwise, box sits on top, and we won't be able to see the text input.
   left_x = -355; # Left_x and top_y used to ensure that the text is left aligned...using x,y, it would be centred!
   top_y = 25;

   text{ caption = "|"; max_text_width = 700; max_text_height = 300; font = "Palatino Linotype"; font_size = 18; font_color = "63,126,188";  background_color = "255,255,255"; text_align = align_left;} Txt_Keyboard_Input;
   left_x = -350;
   top_y = 20;

   text { caption = "Einfach starten einzutippen. Wenn Sie fertig sind, bitte die \n<font color='255,153,51'><b>Tab</b></font> Taste drücken um weiterzumachen."; font_color = "63,126,188"; max_text_width = 1200; font_size = 16; formatted_text = true;} Txt_Instruction2;
   x = 0;
   y = -450;



} P_Keyboard_Input;

#=====================
# 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

        time = 500;  # Audio will play after 500 ms from the beginning of the trial.

    } E_Auditory_Stimulus;
} T_Auditory_Stimulus;

####

# Definition of the Trial to end the session
# Operator Controlled
trial
{
    trial_duration = 1000;

    stimulus_event
    {
        picture P_End_Thanks;
        code = "End of Session!";
    };
    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 = 30;

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_Questionnaire_Text_X;

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.


###################################################
# 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 = 4; # We specify that there can be a maximum of 4 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;


				# 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 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_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.

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


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


				# SPECIFIC FOR 'KNOW
				# For 'Know', we do the following assignments manually BEFORE calling this procedure.
            # So just do their placements here.
				if (Txt_Array_Questionnaire_Texts[V_Row].caption() != " ") then
					# Since there are only a maximum of two/three questionnaire radio button rows in 'KNOW' (unlike the normal radio buttons)
					# we place the questionnaire text on top of the buttons.
					P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[V_Row], V_Questionnaire_Text_X, V_Last_Calculated_Centre_Y+60);
				end;

				#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 = -500; # 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 = 6;


		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.


      #Txt_Message.set_caption(string(N_of_Radio_Button_Rows) + " " + string(AL_Input_Array.count()) + " " + string(A_Radio_Button_Options.count()));
      #Txt_Message.redraw();
      #P_User_Interface.add_part(Txt_Message, 0 ,-500);

		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

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


		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.


      #Txt_Message.set_caption(string(N_of_Radio_Button_Rows) + " " + string(AL_Input_Array.count()) + " " + string(A_Radio_Button_Options.count()));
      #Txt_Message.redraw();
      #P_User_Interface.add_part(Txt_Message, 0 ,-500);

		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 > 250   # 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!!!
###################################################


#preset string V_Version; # Prompt the version at the beginning!!!
string V_Version = scenario_arguments[1]; # Specific for running the scenario using command-line interface;
                                          # scenario_arguments is a built-in 1d string array, that contains the comma-delimited
                                          # strings passed using the -a parameter.  This enables passing arguments
                                          # to the scenario file.  If -a "1,abc" was specified on the command-line,
                                          # then scenario_arguments[1] would be "1" and scenario_arguments[2] would be "abc".
                                          # We use this mechanism to pass the Version to the PCL instead of prompting the user.

int N_of_Trials = 1;                                 # Number of Experimental Trials per Session.

input_file F_Session_List = new input_file;
F_Session_List.open("Session_List_K2_" + V_Version + ".txt");
# This is the file containing the list of stimuli for one session.
# Each line in this file must correspond to one experimental trial.

# Columns of strings in the order found in the input Session List file.
string V_Auditory_Stimulus;
string V_Cover_Story;
string V_Description;

array<string> A_Auditory_Stimulus[0];

# There's only one track for the whole session in Know-2...the same track is played in all trials, with different preceding texts.
# Access the track names, store them in an array.
V_Auditory_Stimulus = F_Session_List.get_line();
#V_Auditory_Stimulus.split(" ",A_Auditory_Stimulus);

V_Cover_Story = F_Session_List.get_line();


system_keyboard.set_delimiter('\t');    # Defines the escape character that will get the control out of the get_input() function.
                                       # \n => Enter. \t => Tab...Pressing this button will get us out of the keyboard mode.
                                       # We've set it to Tab, because that is not as easy to type as enter (because there's no going back) / tab (because it is too dangerously close to ESC).

system_keyboard.set_inactivity_time_out(60000); # 60 second inactivity timeout for keyboard input

system_keyboard.set_case_mode(3); # 1 => CASE_LOWER; 2 => CASE_UPPER; 3 => CASE_SHIFT; 4=> CASE_SHIFT_CAPS;



int V_Hash_Index;

string V_Rating_Scales;
input_file F_Rating_Scales = new input_file;
F_Rating_Scales.open("Rating_Scales.txt");
V_Rating_Scales = F_Rating_Scales.get_line();

array<string> A_Rating_Scales[0];
array<string> A_Rating_Individual_Pairs[0][2];
# This array contains the pairs in 2D ... as in [x][1] = left label and [x][2] = right label
array<string> A_Temp[0];
# Since the split function doesn't seem to be happy with anything other than a 1D array,
# we first split the pairs into that array, and add it into the 2D array above.


int V_Rating_Pair_Counter;


# We have all the Rating-Scales on a single line, each individual Rating-Pair separated by a # in the input.
# Each part of a given Rating-Pair is inturn separated by a - in the input.
# Split the input line into individual questionnaire texts and store the output in an array.

A_Rating_Scales.resize(0); # Empty the array
V_Rating_Scales.split("#",A_Rating_Scales);

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


	# Replace # characters in the input line with line-feed / newline characters.
	V_Hash_Index = V_Cover_Story.find("#");
	loop until V_Hash_Index == 0 begin
		V_Cover_Story.set_char(V_Hash_Index, 10); # 10 -> LF
		V_Hash_Index = V_Cover_Story.find("#");
	end;

	Txt_Description.set_caption(V_Cover_Story);
	Txt_Description.redraw();
	P_User_Interface.add_part(Box_Description, 0, 0);
	P_User_Interface.add_part(Txt_Description, 0, 0);

   V_Origin_Y = -400;
	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 Trials ***/
  int V_Current_Trial = 1

until
  V_Current_Trial > N_of_Trials

begin
	#V_Auditory_Stimulus = F_Session_List.get_string(); # Eg: 01SAI

		# Access and display the Description (Context Text) of the musical tracks to follow
		V_Description = F_Session_List.get_line();

		# Replace # characters in the input line with line-feed / newline characters.
		V_Hash_Index = V_Description.find("#");
		loop until V_Hash_Index == 0 begin
			V_Description.set_char(V_Hash_Index, 10); # 10 -> LF
			V_Hash_Index = V_Description.find("#");
		end;

		Txt_Description.set_caption(V_Description);
		Txt_Description.redraw();
	   P_User_Interface.add_part(Box_Description, 0, 0);
		P_User_Interface.add_part(Txt_Description, 0, 0);

		V_Origin_Y = -550;
		Q_Show_Menu_Boxes({"Abspielen"});

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

		#T_Blank_Screen.present();
		Q_Clear_Previous_Button_And_Menu_Choices();

		V_Origin_Y = 0;


   #============
   # Loop 1.1: -
   #============
	#loop int V_Track_Counter = 1 until V_Track_Counter > 1 begin

		# Do filename and event-code assignments valid during this exp-trial;
		# Load wavefile and bitmap stimuli that are needed for this trial;
		/* We do this before launching the experimental trial so as to keep
		as minimal intereference as possible in trial timings.  You see,
		these things consume processor time, however small they are!
		*/
		####  Specific for presenting Auditory Stimuli   -------------------------------
		Wav_Auditory_Stimulus.set_filename(V_Auditory_Stimulus + ".wav");
		Wav_Auditory_Stimulus.load();

		E_Auditory_Stimulus.set_event_code(V_Auditory_Stimulus + ".wav");
		####

		# Access and display the name of the musical track to follow
		V_Description = F_Session_List.get_line();

		# Replace # characters in the input line with line-feed / newline characters.
		V_Hash_Index = V_Description.find("#");
		loop until V_Hash_Index == 0 begin
			V_Description.set_char(V_Hash_Index, 10); # 10 -> LF
			V_Hash_Index = V_Description.find("#");
		end;

		Txt_Message.set_caption(V_Description);
		Txt_Message.redraw();
		P_User_Interface.add_part(Txt_Message, 0, 100);



		# Play the musical stimulus
		P_User_Interface.add_part(Bmp_Audio_Playing,0,-100);
		P_User_Interface.present();

		# We start playing the audio 500 ms after the beginning of the trial!!!
		# Using the time parameter...see trial definition above.

      T_Auditory_Stimulus.present();

		P_User_Interface.clear();

		# Prepare and show the ratings screen
		V_Selection_Completed = false;
		V_Present_Supplementary_Menu = true;
		V_Supplementary_Menu_Choice_Clicked = 0;

		# No infinite loop for Know-1...unlike MusiTab, because here the radio buttons are shown only after the musical stimulus has ended playing.

		Txt_Message.set_caption("Nachdem Sie sich nun den Ausschnitt angehört haben, wie würden Sie diesen einschätzen?\nBitte nutzen Sie die vorgegebenen Eigenschaftspaare, um uns Ihren Eindruck mitzuteilen.");
		Txt_Message.redraw();
		P_User_Interface.add_part(Txt_Message, 0, 500);

      # Trackwise Ratings
		A_Rating_Scales.shuffle(); # Randomise the elements in the array.


		# Questionnaire 1: Since Questionnaire 1 has 30 Radio Button Rows, we do it in two parts.
      # Part 1 (Ratings 1 to 15)...notice A_Rating_Scales.count()/2

		A_Rating_Individual_Pairs.resize(0); # Empty the array

		loop V_Rating_Pair_Counter = 1 until V_Rating_Pair_Counter > A_Rating_Scales.count()/2 begin
			A_Rating_Scales[V_Rating_Pair_Counter].split("-",A_Temp);
			# Since the split function doesn't seem to be happy with anything other than a 1D array,
			# we first split the pairs into that array, and copy things into the 2D array below.
					#A_Rating_Individual_Pairs.resize(V_Rating_Pair_Counter)(2); # We need to manually increase the array size (since we're not using split).
					#A_Rating_Individual_Pairs[V_Rating_Pair_Counter][1] = A_Temp[1];
					#A_Rating_Individual_Pairs[V_Rating_Pair_Counter][2] = A_Temp[2];
			# THE ABOVE CODE USES AN INCORRRECT METHOD TO RESIZE/ACCESS A 2D ARRAY.  THE CORRECT WAY IS TO USE THE add() METHOD.
			# That increased the count of the array, which necessitated that we divide the count/2 in the PBR procedure, which
			# interacted with the co-ordinates in such a way that the button in the middle of the screen (0,0) was
			# never reset once it was hovered over!
			# Thanks to the following link, we corrected this, and reverted back the PBR procedure to an almost identical copy of it's non_PBR counterpart!
			# REF: http://www.neurobs.com/menu_support/menu_forums/view_thread?id=6827
			A_Rating_Individual_Pairs.add(A_Temp);
			# So basically, we add the 1D array containing two elements as a single element to the 2D array.

		   #A_Rating_Individual_Pairs[V_Rating_Pair_Counter].shuffle(); # Shuffle the pair that we just saved.  Notice that we provide the first dimension here.
																							# Shuffling without dimensions would still work...however,
																							# although 2D structure is accepted to access the array, things are quite chaotic,
																							# sometimes even end up empty (Yes, we tested it!)
																							# In effect, there's no 2D structure preserved as intended anymore.  When doing this
			V_Rating_Pair_Counter =  V_Rating_Pair_Counter + 1;
		end;

		# We are using the pass-by reference here; We didn't do it for other scenarios, because
		# passing-by reference would require that we declare a new array variable, and then pass that array variable.
		# But in the present scenario, that is what is needed.

      Q_Show_Radio_Buttons_PBR(A_Rating_Individual_Pairs);  # Notice that the Pass-By-Reference version is called here!!!
		P_User_Interface.clear();
		Q_Clear_Previous_Button_And_Menu_Choices();


		V_Selection_Completed = false;
		V_Present_Supplementary_Menu = true;
		V_Supplementary_Menu_Choice_Clicked = 0;

		Txt_Message.set_caption("Nachdem Sie sich nun den Ausschnitt angehört haben, wie würden Sie diesen einschätzen?\nBitte nutzen Sie die vorgegebenen Eigenschaftspaare, um uns Ihren Eindruck mitzuteilen.");
		Txt_Message.redraw();
		P_User_Interface.add_part(Txt_Message, 0, 500);

		# Questionnaire 1: Since Questionnaire 1 has 30 Radio Button Rows, we do it in two parts.
      # Part 2 (Ratings 16 to 30).

		A_Rating_Individual_Pairs.resize(0); # Empty the array

		loop until V_Rating_Pair_Counter > A_Rating_Scales.count() begin
			A_Rating_Scales[V_Rating_Pair_Counter].split("-",A_Temp);
		   # See above in the loop for Part 1 for some detailed comments
			# REF: http://www.neurobs.com/menu_support/menu_forums/view_thread?id=6827
			A_Rating_Individual_Pairs.add(A_Temp);
			# So basically, we add the 1D array containing two elements as a single element to the 2D array.

			V_Rating_Pair_Counter =  V_Rating_Pair_Counter + 1;
		end;

		# We are using the pass-by reference here; We didn't do it for other scenarios, because
		# passing-by reference would require that we declare a new array variable, and then pass that array variable.
		# But in the present scenario, that is what is needed.

      Q_Show_Radio_Buttons_PBR(A_Rating_Individual_Pairs);  # Notice that the Pass-By-Reference version is called here!!!
      P_User_Interface.clear();
		Q_Clear_Previous_Button_And_Menu_Choices();

		T_Blank_Screen.present();
		Q_Clear_Previous_Button_And_Menu_Choices();

		####  Specific for presenting Auditory Stimuli   -------------------------------
		# Unload all memory occupiers such as wavefile stimuli.
		Wav_Auditory_Stimulus.unload();
		####

      # Go to the Next Track inside this trial
      #V_Track_Counter = V_Track_Counter + 1;

	#=============
	# End Loop 1.1
	#=============
	#end; /*** End Loop 1.1 for Tracks inside a trial ***/


   # There's no extensive questionnaires in Know 2 unlike Know 1.
   # Just the session final one...see blow.


	T_Blank_Screen.present();
	Q_Clear_Previous_Button_And_Menu_Choices();


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



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


# Here comes the session final questionnaire & Participant Input


   # SPECIFIC for 'KNOW'
   # Since KNOW has the usual radio button scales during the trial followed by text-questionnaires in-between the trials,
   # we decided to tweak V_Button_Gap every time before the text-questionnaires such that there would be
   # ample splace between the buttons rows to place the questionnaire text.
   # At the end of this questionnaire saga before going to the next trial of audio presentations and the usual radio buttons,
   # we reset it back to its default value (currently the time-tested value of 30).

   V_Button_Gap = 100;  # Tweak the button gap...to reset it after the text-questionnaires...see below.

   #V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[1].width())/2;  # SEE WAY ABOVE for explanation of why we're doing it this way...keyword: left-alignment with no option to provide left_x in add_part...look for V_Questionnaire_Text_X.
                                                                                     # For instances in which we call Q_Show_Radio_Buttons to place buttons and questionnaire texts, this is done in that procedure above.
                                                                                     # But here, we place questionnaire texts manually...so this alsoneeds to be done here before that.
	#P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[1], V_Questionnaire_Text_X, 0);

   V_Questionnaire_Texts = F_Session_List.get_line();
   Txt_Message.set_caption(V_Questionnaire_Texts);
   Txt_Message.redraw();

   P_User_Interface.add_part(Txt_Message, 0, 300);

	V_Questionnaire_Texts = F_Session_List.get_line();
	Txt_Array_Questionnaire_Texts[1].set_caption(V_Questionnaire_Texts);
	Txt_Array_Questionnaire_Texts[1].redraw();

   V_Present_Supplementary_Menu = false;
	Q_Show_Radio_Buttons({{"<b>gar nicht gefallen</b>","<b>sehr gut gefallen</b>"}});
	P_User_Interface.clear();
	Q_Clear_Previous_Button_And_Menu_Choices();

   # First Yes-No Question & Co.

	V_Questionnaire_Texts = F_Session_List.get_line();
	Txt_Array_Questionnaire_Texts[1].set_caption(V_Questionnaire_Texts);
	Txt_Array_Questionnaire_Texts[1].redraw();
   V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[1].width())/2;  # SEE WAY ABOVE for explanation of why we're doing it this way...keyword: left-alignment with no option to provide left_x in add_part...look for V_Questionnaire_Text_X.
                                                                                     # For instances in which we call Q_Show_Radio_Buttons to place buttons and questionnaire texts, this is done in that procedure above.
                                                                                     # But here, we place questionnaire texts manually...so this alsoneeds to be done here before that.
	P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[1], V_Questionnaire_Text_X, 0);

   V_Origin_Y = -100;
	Q_Show_Menu_Boxes({"Ja","Nein"});
	P_User_Interface.clear();
	Q_Clear_Previous_Button_And_Menu_Choices();
   V_Origin_Y = 0;

	# Regardless of the answer, read the two questions from the session list.

	V_Questionnaire_Texts = F_Session_List.get_line();
	Txt_Array_Questionnaire_Texts[1].set_caption(V_Questionnaire_Texts);
	Txt_Array_Questionnaire_Texts[1].redraw();

	V_Questionnaire_Texts = F_Session_List.get_line();
	Txt_Array_Questionnaire_Texts[2].set_caption(V_Questionnaire_Texts);
	Txt_Array_Questionnaire_Texts[2].redraw();

   if (V_Menu_Choice_Clicked == 1) then # Display the questions; else do nothing.

		Q_Show_Radio_Buttons({{"<b>wenig vertraut</b>", "<b>sehr vertraut</b>"},{"<b>mag ich gar nicht</b>","<b>mag ich sehr</b>"}});
		P_User_Interface.clear();
		Q_Clear_Previous_Button_And_Menu_Choices();

	end;

   # Second Yes-No Question & Co.

	V_Questionnaire_Texts = F_Session_List.get_line();
	Txt_Array_Questionnaire_Texts[1].set_caption(V_Questionnaire_Texts);
	Txt_Array_Questionnaire_Texts[1].redraw();
	V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[1].width())/2;
	P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[1], V_Questionnaire_Text_X, 0);

   V_Origin_Y = -200;
	Q_Show_Menu_Boxes({"Ja","Nein"});
	P_User_Interface.clear();
	Q_Clear_Previous_Button_And_Menu_Choices();
   V_Origin_Y = 0;

	# Regardless of the answer, read the two questions from the session list.

	V_Questionnaire_Texts = F_Session_List.get_line();
	Txt_Array_Questionnaire_Texts[2].set_caption(V_Questionnaire_Texts);
	Txt_Array_Questionnaire_Texts[2].redraw();

	V_Questionnaire_Texts = F_Session_List.get_line();
	Txt_Array_Questionnaire_Texts[3].set_caption(V_Questionnaire_Texts);
	Txt_Array_Questionnaire_Texts[3].redraw();

   if (V_Menu_Choice_Clicked == 1) then # Display the questions; else do nothing.

		Txt_Array_Questionnaire_Texts[1].set_caption(Txt_Array_Questionnaire_Texts[1].caption() + " : <b>" + Txt_Array_Menu_Options[V_Menu_Choice_Clicked].caption() + "</b>");
		Txt_Array_Questionnaire_Texts[1].redraw();

		V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[1].width())/2;
		P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[1], V_Questionnaire_Text_X, 0);

		V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[2].width())/2;
		P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[2], V_Questionnaire_Text_X, -100);

		V_Origin_Y = -250;
		Q_Show_Menu_Boxes({"1+","10+","25+","50+"});
		P_User_Interface.clear();
		Q_Clear_Previous_Button_And_Menu_Choices();

		V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[1].width())/2;
		P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[1], V_Questionnaire_Text_X, 0);

		Txt_Array_Questionnaire_Texts[2].set_caption(Txt_Array_Questionnaire_Texts[2].caption() + " : <b>" + Txt_Array_Menu_Options[V_Menu_Choice_Clicked].caption() + "</b>");
		Txt_Array_Questionnaire_Texts[2].redraw();
      V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[2].width())/2;
		P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[2], V_Questionnaire_Text_X, -100);

		V_Questionnaire_Text_X = -690 + int(Txt_Array_Questionnaire_Texts[3].width())/2;
		P_User_Interface.add_part(Txt_Array_Questionnaire_Texts[3], V_Questionnaire_Text_X, -200);

		V_Origin_Y = -350;
		Q_Show_Menu_Boxes({"Gestern","letzte Woche","letzter Monat","letztes Jahr/+"});
		P_User_Interface.clear();
		Q_Clear_Previous_Button_And_Menu_Choices();

		V_Origin_Y = 0;


	end;

   # Specific for KNOW
   # Reset the Button Gap to its original/default value
   V_Button_Gap = 30;


		Txt_Description.set_caption("Hier ist das Experiment <i>Historische Aufführungspraxis</i> zu Ende.");
		Txt_Description.redraw();
	   P_User_Interface.add_part(Box_Description, 0, 0);
		P_User_Interface.add_part(Txt_Description, 0, 0);

		V_Origin_Y = -550;
		Q_Show_Menu_Boxes({"OK"});
		P_User_Interface.clear();
		Q_Clear_Previous_Button_And_Menu_Choices();

		V_Origin_Y = 0;



/*
# And here comes the clarification text

		# Access and display the clarification text.
		V_Description = F_Session_List.get_line();

		# Replace # characters in the input line with line-feed / newline characters.
		V_Hash_Index = V_Description.find("#");
		loop until V_Hash_Index == 0 begin
			V_Description.set_char(V_Hash_Index, 10); # 10 -> LF
			V_Hash_Index = V_Description.find("#");
		end;

		Txt_Description.set_caption(V_Description);
		Txt_Description.redraw();
	   P_User_Interface.add_part(Box_Description, 0, 0);
		P_User_Interface.add_part(Txt_Description, 0, 0);

		V_Origin_Y = -550;
		Q_Show_Menu_Boxes({"Zu Ende."});
		P_User_Interface.clear();
		Q_Clear_Previous_Button_And_Menu_Choices();

		V_Origin_Y = 0;

*/
# Close all the open files
F_Session_List.close();
#F_Questionnaire_Texts.close();

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