Hi, this has been bugging me for AGES!
I know I shouldn't really use system calls (like cls, and whatnot), but it's easier than writing my own and I'd prefer not to resort to OPTION 5. Anyways, my code is below. Essentially you pass a vector of strings each set up as an option in a menu into the function, and it displays them, and you can choose the option you want by clicking with the mouse on the option.
The parameters are as follows:
vector<string> Options - Your Menu
bool CountSpaces=true - you may want to make your code more visually pleasing, so you can 'push_back()' this (""), and by setting this false it won't count them.
int X_Offset=-1,
int Y_Offset=-1 - for positioning the menu. Leave negative for the function do decide where to put it, depending on where the cursor currently is.
Return value - The position of the option (from 0 to Options.size()
Anyway. Logically, one would want to clear the menu before/after selection, but when I try this with my lazy way out, the menu function (below), doesn't work. Does anyone know why this may be? (Sorry for the not nice formatting - there was some mess up in copying and pasting).
Code:
#include <conio.h> // Most of the headers are not needed, and are used for other purposes in the program
#include <time.h>
#include <windows.h>
#include <tchar.h>
#include <cctype>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
void Color ( int BackgroundColor, int TextColor )
{
int SeclectedColor = (16*BackgroundColor) + (TextColor);
HANDLE hConsole;
hConsole = GetStdHandle ( STD_OUTPUT_HANDLE );
SetConsoleTextAttribute ( hConsole, SeclectedColor );
}
void GotoXY ( int X, int Y )
{
COORD Cursor_Position;
Cursor_Position.X = X;
Cursor_Position.Y = Y;
SetConsoleCursorPosition( GetStdHandle ( STD_OUTPUT_HANDLE ), Cursor_Position );
}
int Menu ( vector<string> Options, bool CountSpaces=true, int X_Offset=-1, int Y_Offset=-1 )
// HighlightColor is for the color the item will be highlighted to
{ // when mouse hovers over it. X and Y Offsets are for positioning menu
DWORD Event_Count,
Input_Size;
INPUT_RECORD Record_Input;
MOUSE_EVENT_RECORD Mouse;
const int NumOptions = (int)Options.size(),
BLACK = 0, // Colors for highlighting.
GREY = 8,
BRIGHTWHITE = 15;
int CurrentOption = -1, // Currently selected option
Longest = 1, // Longest menu option.
i = 0;
bool OnOption = false; // Is an option selected? true if yes, false if no
if ( X_Offset < 0 ) // Error checking.
{
X_Offset = 0;
}
if ( Y_Offset <= 0 ) // If you just want the menu to be at the cursor's current y-position.
{
CONSOLE_SCREEN_BUFFER_INFO YInfo;
GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &YInfo );
Y_Offset = YInfo.dwCursorPosition.Y+1 ;
}
vector<string>::iterator OptionsIterator;
for ( OptionsIterator=Options.begin(), i=0;
OptionsIterator!=Options.end();
OptionsIterator++, i++ ) // Prints the initial menu.
{
int CurrentLength = (int)Options[i].size();
if ( CurrentLength > Longest ) Longest = CurrentLength;
GotoXY( X_Offset, i+Y_Offset);
cout<< *OptionsIterator;
}
for ( int i=0; i<NumOptions; i++ ) // Appends each option to the same length with whitespaces,
{ // for highlighting purposes.
int TempLen;
TempLen = (int)Options[i].size();
if ( Options[i] != "" )
{
for ( int j=TempLen; j<Longest+1; j++ )
{
Options[i] += ' ';
}
}
}
int X = 0, // X and Y coordinates of mouse in console window, not
Y = 0; // needed, but it makes the code it visually much simpler.
while ( true )
{
GetNumberOfConsoleInputEvents ( GetStdHandle ( STD_INPUT_HANDLE ), &Event_Count );
if ( Event_Count != 0 )
{
ReadConsoleInput ( GetStdHandle ( STD_INPUT_HANDLE ), & Record_Input, 1, & Input_Size );
if ( Record_Input.EventType == MOUSE_EVENT )
{
Mouse = Record_Input.Event.MouseEvent;
Y = Mouse.dwMousePosition.Y,
X = Mouse.dwMousePosition.X;
if ( OnOption ) // For if something is already selected. This had to go first cause
{ // otherwise multiple things may be selected.
if ( CurrentOption != Y-Y_Offset ||
X > (Longest + X_Offset) ||
X < (0 + X_Offset) )
{
OnOption = false;
GotoXY( X_Offset, CurrentOption+Y_Offset );
Color( BRIGHTWHITE, BLACK ); // Changes color.
cout<< Options[CurrentOption];
Color( BLACK, BRIGHTWHITE ); // Changes it again.
}
else if ( GetAsyncKeyState( VK_LBUTTON ) )
{
if ( Options[CurrentOption] != "" )
{
GotoXY( X_Offset, CurrentOption+Y_Offset );
Color( GREY, BRIGHTWHITE ); // Changes color.
cout<< Options[CurrentOption];
Color( BRIGHTWHITE, BLACK ); // Changes it again.
GotoXY( 0, NumOptions + Y_Offset + 1 );
int Blanks = 0;
if ( CountSpaces )
{
for ( int i=0; i<CurrentOption; i++ )
{
if ( Options[i] == "" ) Blanks ++;
}
}
return ( CurrentOption - Blanks ); // if button pressed, returns the current option.
}
}
}
if ( Y >= (0 + Y_Offset) && Y < (NumOptions + Y_Offset) &&
X >= (0 + X_Offset) && X < (Longest + X_Offset) ) // selects things
{
OnOption = true; // something is selected, so true.
CurrentOption = Y - Y_Offset;
GotoXY( X_Offset, Y );
Color( BLACK, BRIGHTWHITE );
cout<< Options[CurrentOption];
Color( BRIGHTWHITE, BLACK );
}
}
}
}
return -1;
}
I reckon just try it out with something like this:
Code:
vector<string> options;
int Selection = -1;
cout<< endl << "Please make a selection from the following options: "
<< endl;
options.clear();
options.push_back( "* Start new game" );
options.push_back( "" );
options.push_back( "* Options" );
options.push_back( "" );
options.push_back( "* Load old game" );
options.push_back( "* Save this game" );
options.push_back( "" );
options.push_back( "* Delete old savegame" );
options.push_back( "" );
options.push_back( "* Exit" );
Selection = Menu( options, true, 2 );
and try a
before it. And it shouldn't work. As I said, this has been bugging me for AGES! Any thoughts would be appreciated.
EDIT - It's meant for a defaulted white background. So if it's black swap the BLACK and BRIGHTWHITE integers I guess