GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 18-Aug-2006, 15:30
BullBuchanan BullBuchanan is offline
New Member
 
Join Date: Aug 2006
Posts: 3
BullBuchanan is on a distinguished road

need help with a console menu system


well I've been grinding on this and another project all day for three days straight and needless to say, I'm shot.

what I need to do is create a menu system in console, that draws in it's options using file input. the file layout is in the following format.

Title
# of Options
The names of the options, one per line

in the options section, a sub-menu is indicated by the following

MENU "OptionName" "filename.mnu"

an option with no functionality is listed in the format as follows

OPTION "OptionName"


The menu is required to be fullscreen, the options must be scrollable with the arrow keys, and the current option must be highlited in some way. In addition, an exit option must be added to the list of every menu. When exit is selected it must return to the previous menu via a singly linked list. Pressing ENTER on an option with no submenu is to yield no result.

if you can't make sense of what is happening in a specific part of my code, or are unsure of some of my classes please feel free to ask. I'm aware that I may have to start from scratch, but I'm completely out of ideas, and at the very least i need a gameplan for a new system if nothing here is salvageable.

CPP / C++ / C Code:
#include <iostream>
using namespace std;
#include <fstream>
#include <string>
#include "SLList.h"
#include "DynArray.h"
#include <conio.h> 
#include <stdio.h>
#include <vector>
#include "Console.h"
#define UP 0x48
#define DOWN 0x50
#define ENTER 13
#define ESC 27
struct menu
{
	string filename;
	string title;
	int numOptions;
	bool subMenu;

	menu() {};
	void menuFill(string fileName, DynArray<menu>& menuList)
	{

		if(menuList.capacity() > 0)
		{
			menuList.clear();
		}
		string temp;
		string temp2;
		string temp3;
		menu a;
		a.filename = fileName;
		if(a.filename[0] == '\"')
		{
			a.filename.erase(a.filename.begin());
			a.filename.erase(--a.filename.end());
		}
		ifstream fin(a.filename.c_str());
		getline(fin, a.title);
		getline(fin, temp);
		a.numOptions = atoi(temp.c_str());
	
	for(int i = 0; i < a.numOptions; i++)
	{
		fin >> temp2;
		if(temp2 == "MENU")
		{
			a.subMenu = 1;
			fin >> a.title;
			while(a.title[(int)(a.title.length()) - 1] != '\"')
			{
				fin >> temp3;
				a.title.push_back(' '); 
				a.title	+= temp3;
			}
			if(a.title[0] == ' ')
		{
			a.title.erase(a.title.begin());
		}
			if(a.title[0] == '\"')
		{
			a.title.erase(a.title.begin());
			a.title.erase(--a.title.end());
		}
			fin >> a.filename;
			if(a.filename[0] == '\"')
		{
			a.filename.erase(a.filename.begin());
			a.filename.erase(--a.filename.end());
		}
			menuList.append(a);
			
		}
		else if(temp2 == "OPTION")
		{
			a.subMenu = 0;
			getline(fin, a.title);
			if(a.title[0] == ' ')
		{
			a.title.erase(a.title.begin());
		}
			if(a.title[0] == '\"')
		{
			a.title.erase(a.title.begin());
			a.title.erase(--a.title.end());
		}
			menuList.append(a);

		}
	}


	fin.close();
	}	

void show(DynArray<menu>& menuList)
{
	for(int i = 0; i < menuList[0].numOptions; i++)
		cout << menuList[i].title << '\n';
}

menu& operator=(const menu& m)
{
	if(this == &m)
		return *this;

	filename = m.filename;
	numOptions = m.numOptions;
	title = m.title;
	subMenu = m.subMenu;
	return *this;
	
}
menu(menu& m)
{
	filename = m.filename;
	numOptions = m.numOptions;
	title = m.title;
	subMenu = m.subMenu;
}

};
int menuDraw(DynArray<menu>& list, SLList<menu>& sList, SLLIter<menu>& iter);

int main(void)
{
	DynArray<menu> menuList;
	DynArray<string> menuItems;
	SLList<menu> menuSLL;
	SLLIter<menu> menuIter(menuSLL);

		
	
	menu mainMenu;
	mainMenu.menuFill("main.mnu", menuList);

	mainMenu.show(menuList);
int menuChoice = 0;


menuChoice = menuDraw(menuList, menuSLL, menuIter);
	menuSLL.addHead(mainMenu);
cout << menuChoice << '\n';
while(menuChoice != menuList.size() && menuList[menuChoice].subMenu)
{
	menu otherMenu;
	otherMenu.menuFill(menuList[menuChoice].filename.c_str(), menuList);
	otherMenu.show(menuList);
	menuChoice = menuDraw(menuList, menuSLL, menuIter);
}

	return 0;
}
int menuDraw(DynArray<menu>& list, SLList<menu>& sList, SLLIter<menu>& iter)
{
	int choice = 0;
	char charVal = '*';
while(true)
{
	if (_kbhit ())
      {
		  
            // show stuff for each specific move
             if(FS::con.keyPressed(VK_UP))   
            {
				if(choice > 0)
					choice--;
               
            } 

			 else if(FS::con.keyPressed(VK_DOWN))   
              {
				if(choice < list.size())
					choice++;
              
			}

			 else if(FS::con.keyPressed(VK_RETURN))   
             {
				 if(choice == list.size())
				 {
					menu sbMnu;
					sList.addHead(sbMnu);
					list.clear();
					list.append(iter.current());

					list[0].show(list);
					sbMnu.menuFill(list[0].filename.c_str(), list);
					
					sbMnu.show(list);
					choice = menuDraw(list, sList, iter);*/
				 }
				 else if(choice == list.size() and sList.head == NULL)
					 return -1;
				 else if(list[choice].subMenu)
					return choice;
				
			} 
			 
			
	}

}
}

DynArray.h
CPP / C++ / C Code:
#ifndef DYNARRAY_H_
#define DYNARRAY_H_
template <typename Type>
class DynArray
{
private:
	int arrSize;
	int cap;
	int index;
	Type* arr;
	

public:

	explicit DynArray(int initialSizeAndCap = 0) {arrSize =  initialSizeAndCap; cap = initialSizeAndCap; arr = new Type[initialSizeAndCap];}
	virtual ~DynArray() {clear();}

	Type& operator[](int index) {return arr[index];}
	
	int size() {return arrSize;}
	void append(Type& item)
	{
		if(size() == 0)
		{	
			Type* temp = new Type[1];
			arr = temp;
			cap = 1;
			arrSize = 0;
			arr[arrSize] = item;
			arrSize++;
		}
			
		else if(size() < cap)
		{
			arr[arrSize] = item;
			arrSize++;
		}
		else
		{
		
			Type* temp = new Type[2 * arrSize];
			for(int i = 0; i < arrSize; i++)
				temp[i] = arr[i];

			delete [] arr;
			arr = temp;
			cap = arrSize * 2;
			arr[arrSize] = item;
			arrSize++;
		}
		
		
	}
	int capacity() {return cap;}
	void clear(){arrSize = 0; cap = 0; delete [] arr;}
	DynArray& operator=(DynArray& d)
	{
		if(this == &d)
			return *this;

		this->arrSize = d.arrSize;
		this->cap = d.cap;
		this->index = d.index;
		

		for(int i = 0; i < d.arrSize; i++)
			this->append((d[i]));

		return *this;
	}

	DynArray(DynArray& d)
	{

		this->arrSize = d.arrSize;
		this->cap = d.cap;
		this->index = d.index;
		

		for(int i = 0; i < d.arrSize; i++)
			this->append(d[i]);

	
	}


};

#endif

SLList.h
CPP / C++ / C Code:
template<typename Type>
class SLLIter;

template<typename Type>
class SLList
{
	friend SLLIter<Type>;

private:
	struct Node
	{
		Type element;
		Node* next;
		
	};

	Node* head;

public:

	// SLList : constructor.
	SLList() {head = 0;}

	// ~SLList : destructor.
	virtual ~SLList() {};

	// operator = : assignment operator.
	// NOTE : invalidates all iterators to this list.
	SLList<Type> &operator=(const SLList<Type> &list)
	{
		clear();
		if(!list.head)
		return *this;

		else
			recursive(list.head);

			return *this;
	}


	// addHead : append a new item to the front of the list.
	void addHead(const Type &v)
	{
			Node* temp = new Node;
			temp->element = v;
		
		//if(head)
		//{
			temp->next = head;
			head = temp;
		//}
		//else
		//{
		//	temp->next = 0;
		//	head = temp;
		//}
			
	}

	// clear : clear out the list
	void clear()
	{
		while(head)
		{
			Node* temp = head;
			head = head->next;
			delete temp;
		}
		
	}


	// insert : place a value before the given iterator
	//          location.  Don’t insert at a bad location.
	void insert(SLLIter<Type> &index, const Type &v)
	{
		Node* temp = new Node;
		temp->element = v;
		temp->next = index.location;
		if(index.previous)
			index.previous->next = temp;

		else
			head = temp;

		index.location = temp;
		/*if(!head)
		{
			addHead(v);
			index.location = head;
		}
		else
		{
			Node* temp = new Node;
		    temp->element = v;
			index.previous->next = temp;
			temp->next = index.location;
		
			index.location = temp;
		}*/
	}


	// remove : remove the value at the given iterator
	//          location.  Don’t remove at a bad location.
	void remove(SLLIter<Type> &index)
	{
		Node* temp = index.location;
		
		if(index.previous)
			index.previous->next = temp->next;

		else
			head = temp->next;

		index.location = temp->next;
		delete temp;

		/*if(head == 0)
		{
			clear();
			return;
		}

		if(index.location == head)
		{
			Node* temp = head;
			head = head->next;
			delete temp;
			
			index.location = head;
		}
		
		else
		{
			Node* temp = index.location;
			index.previous->next = index.location->next;
			index.location = index.location->next;
			delete temp;

		}*/
	}
	
	
	void recursive(Node* n)
	{
		if(n == NULL)
			return;
		recursive(n->next);
		addHead(n->element);
	}

};


template<typename Type>
class SLLIter
{
	friend SLList<Type>;
private:
	SLList<Type> *list;
	
	typename SLList<Type>::Node* previous;
	typename SLList<Type>::Node* location;
	
public:

	//template<typename Type>
	// SLLIter : constructor.
	SLLIter(SLList<Type> &listToIterate)
	{
		list = &listToIterate;
		previous = 0;
		location = list->head;

	}
	// ~SLLIter : destructor.
	virtual ~SLLIter () {};

	// begin : move the iterator to the front of the list
	void begin ()
	{	location = list->head;
		previous = 0;
	}

	


	// end : only return true when iterator is beyond the last //       item
	bool end ()
	{
		if(location == NULL)
			return true;
		else
			return false;
	}

	//template<typename Type>
	// operator++ : prefix (only) ++ operator
	SLLIter<Type> &operator++ ()
	{
		previous = location;
		location = location->next;
		return *this;
	}

	//template<typename Type>
	// current : extract the element at the current location.
	Type &current ()
	{
		return location->element;
	}

	

};


Console.h
CPP / C++ / C Code:
// Console.h : Add support for some interesting console tricks.

#ifndef CONSOLE_H_
#define CONSOLE_H_

// Link the appropriate Console library.
#ifdef _DEBUG
	#pragma comment(lib, "ConsoleD")
#else
	#pragma comment(lib, "ConsoleR")
#endif

// Don't bring in quite so much stuff.
#define WIN32_LEAN_AND_MEAN
// The following is so we can use "GetConsoleWindow()".
#define _WIN32_WINNT 0x0500
#include <windows.h>

#include <ostream>
#include <stdexcept>
using std::out_of_range;
#include <exception>
using std::bad_exception;
#include <sstream>
#include <string>
#include <iomanip>

// One day exception specifications will be fully supported...
#pragma warning(disable:4290)

// Just for Full Sail.
namespace FS
{

// A character attribute.  Color primarily but see the CHAR_INFO Help for more options.
typedef WORD Attr;
// Handy built-in colors for all to use.  Specifying BLACKOUT makes both the fore- and back-ground colors black.
extern const Attr DEF, BLACKOUT, DARKRED, DARKGREEN, DARKBLUE, DARKYELLOW, DARKMAGENTA, DARKCYAN,
	LIGHTGRAY, DARKGRAY, RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, WHITE,
	BGDARKRED, BGDARKGREEN, BGDARKBLUE, BGDARKYELLOW, BGDARKMAGENTA, BGDARKCYAN,
	BGLIGHTGRAY, BGDARKGRAY, BGRED, BGGREEN, BGBLUE, BGYELLOW, BGMAGENTA, BGCYAN, BGWHITE;

// The console window.
typedef std::ostream Output;
typedef Output & (*OutputPF)(Output &); // Function pointers are our friends.
class Console : public Output
{
	public:
		// A 2D picture, comfortably nested.
		class Image
		{
			// What to display.
			CHAR_INFO *chiBuffer;

			// How tall and wide it is.
			int rows, cols;

			// Make us nothingness.
			void clear()
			{
				this->chiBuffer = 0;
				this->rows = this->cols = 0;
			}

			// Give back our RAM.
			void free()
			{
				delete [] this->chiBuffer;
			}

			// Efficiently procure space for our dynamic memory.
			//
			// In:	cols	The number of columns we'll have.
			//		rows	The number of rows we'll have.
			void reallocate(int cols, int rows);

			// Deep duplicate a CHAR_INFO array.
			//
			// In:	cols	The number of columns we'll have.
			//		rows	The number of rows we'll have.
			//		ci		A CHAR_INFO for each cell (cols * rows).
			void DeepCopy(int cols, int rows, CHAR_INFO const ci[]);

		public:
			// Create a 2D picture.
			//
			// In:	img		An array of strings containing the characters to display.
			//		rows	The height of "img" (1+).  The width is assumed to be the length of the first string and should be the same for all the strings, i.e., the picture
			//					is rectangular.
			//		attr	Character attributes to use for every cell.  Color primarily but see the CHAR_INFO Help for more options.
			Image(const wchar_t * const img[] = 0, int rows = 0, Attr attr = 0);
			// Create a 2D picture.
			//
			// In:	cols	How many columns each row has (1+).
			//		rows	How many rows it has          (1+).
			//		ci		A CHAR_INFO for each cell	  (rows * cols).
			Image(int cols, int rows, CHAR_INFO const ci[]);
			// Create a 2D picture.
			//
			// In:	fileName	Where to get our information from.
			Image(std::string const &fileName) throw(ios_base::failure &, bad_exception &);
			// Create a 2D picture.
			//
			// In:	cols	How many columns each row has (1+).
			//		rows	How many rows it has          (1+).
			//
			// Note:	The image's cells are not initialized.
			Image(int cols, int rows) :	cols(cols < 1 ? 1 : cols),
										rows(max(rows, 1))
			{
				this->chiBuffer = new CHAR_INFO[this->rows * this->cols];
			}
			// Copy constructor.
			//
			// In:	i	An existing one to mimic.
			Image(const Image &i);
			// Assignment operator.
			//
			// In:	i	An existing one to emulate.
			Image & operator =(const Image &i);
			// Destructor.
			virtual ~Image() { this->free(); }

			// Return:	Our buffer, read-only.
			const CHAR_INFO *getChiBuffer() const { return this->chiBuffer; }

			// Return:	Our height (1+).
			int getRows() const { return this->rows; }

			// Return:	Our width (1+).
			int getCols() const { return this->cols; }

			// Define a 2D picture.
			//
			// In:	img		An array of strings containing the characters to display.
			//		rows	The height of "img" (1+).  The width is assumed to be the length of the first string and should be the same for all the strings, i.e., the picture
			//					is rectangular.
			//		attr	Character attributes to use for every cell.  Color primarily but see the CHAR_INFO Help for more options.
			void set(const wchar_t * const img[], int rows, Attr attr);

			// Create a 2D picture.
			//
			// In:	cols	How many columns each row has (1+).
			//		rows	How many rows it has          (1+).
			//		ci		A CHAR_INFO for each cell	  (rows * cols).
			void set(int cols, int rows, CHAR_INFO const ci[]);

			// Define a 2D picture.
			//
			// In:	i	An existing one to clone.
			void set(const Image &i);

			// Return:	true if we can be successfully displayed.
			bool good() const
			{
				return this->chiBuffer && this->rows > 0 && this->cols > 0;
			}

			// Get access to one of our rows.
			//
			// In:	i	The index (0 -=> rows - 1) of the one to retrieve.
			//
			// Return:	The address of the first CHAR_INFO in the row - use another [] to
			//				access a specific column.
			CHAR_INFO * operator [](int i) throw(out_of_range &, bad_exception &);
			// Read-only version for constant objects.
			CHAR_INFO const * operator [](int i) const throw(out_of_range &, bad_exception &);

			// Store an Image to a file.
			//
			// In:	fileName	Where to send our information to.
			void Save(std::string const &fileName) const throw(ios_base::failure &, bad_exception &);

			// Retrieve an Image from a file.
			//
			// In:	fileName	Where to get our information from.
			void Load(std::string const &fileName) throw(ios_base::failure &, bad_exception &);
		};

	private:
		// Where our output goes.
		HANDLE out;
		// Where our input comes from.
		HANDLE in;
		// The visible screen buffer.
		HANDLE vis;
		// DirectDraw, for WaitForVerticalBlank().
		HINSTANCE ddrawLib;
		// Secretly an IDirectDraw7 *, for WaitForVerticalBlank().
		void *DDobject;
		// Do we bother to WaitForVerticalBlank()?
		bool w4VB;

		// How many columns our console window has (0+).
		int cols;
		// How many lines our console window has (0+).
		int rows;

		// Our current background (high nibble) and foreground (low nibble) colors & more.
		Attr attrs;

		// Our Windows handle.
		HWND hwnd;

		// The coords of any little scrollable window area within the screen.
		int wleft, wtop, wright, wbottom;

		// Are we back-buffered?
		bool bb;

		// Default constructor.
		Console();

		// Return:	true if the standard output screen buffer is currently visible.
		bool StdIsVis() const;

		// Perform a "safe" newline, i.e., one which preserves our colors.
		void nl(void) const;

		// Print something to the output.
		//
		// In:	ch	The character to show.
		template <typename Type>
		void put(Type ch) const
		{
			if ('\n' == ch)
				// Color safe!
				nl();
			else if ('\t' == ch)
			{
				// Thinner tabs.
				const int Width = 4;
				int x, y;
				CP(x, y);
				int pos = (x / Width + 1) * Width;
				if (pos >= cols)
					// Wrap.
					nl();
				else
					// Jump.
					Goto(y, pos);
			}
			else
			{
				// Nuthin' special.
				wchar_t c = ch;
				DWORD dummy;
				WriteConsole(out, &c, 1, &dummy, NULL);
			}
		}

		// Make sure a box's dimensions make sense.
		//
		// I/O:	left	The left coordinate of the area (l -> r, <= right).
		//		top		The top coordinate of the area (t -> b, <= bottom).
		//		right	The right coordinate of the area (l -> r, >= left).
		//		bottom	The bottom coordinate of the area (t -> b, >= top).
		//
		// In:	l, t, r, b	Acceptable left, top, right and bottom coordinates.
		void BoxCheck(int &left, int &top, int &right, int &bottom, int l, int t, int r, int b) const;
		void BoxCheck(int &left, int &top, int &right, int &bottom) const
		{
			BoxCheck(left, top, right, bottom, 0, 0, cols - 1, rows - 1);
		}

		// Format and display something as a string.
		//
		// In:	v	The value to use the insertion operator with.
		template <typename T>
		void T2String(const T &v)
		{
			std::wostringstream oss;
			oss.flags(flags());
			oss.width(width());
			oss.fill(fill());
			oss.precision(precision());
			oss << v;
			std::wstring const &s = oss.str();
			if (std::wstring::npos == s.find_first_of(L"\n\t"))
				// It's clear - dump it quick.
				putRawString(s);
			else
			{
				// Darn, special formatting.
				for (std::wstring::const_iterator i = s.begin(); i != s.end(); i++)
					put(*i);
			}
			width(0); // Reset.
		}

		// What are the dimensions of our client area, in pixels?
		//
		// Out:	width	How wide we are.
		//		height	How tall we are.
		//
		// Return:	true if we're windowed, false if full screen.
		bool getClientDim(int &width, int &height) const;

	public:
		// Singletons are our friends!
		//
		// Return:	The only object.
		static Console &GetTheOnlyInstance()
		{
			// There can be only one.
			static Console c;
			return c;
		}
		// Destructor.
		virtual ~Console(void);

		// Return:	How many columns our console window has (0+).
		int Cols(void) const { return cols; }
		// Return:	How many lines our console window has (0+).
		int Rows(void) const { return rows; }

		// Clear the entire screen or just our limited window.  This leaves the cursor in the
		//	upper-left corner o' whatever area it just wiped.
		//
		// In:	window	true to limit ourselves to our box.
		void Clear(bool window = true) const;

		// Clear a line.  The cursor doesn't move.
		//
		// In:	r		The row to wipe (0 -> "Rows()" - 1).
		//		window	true to limit ourselves to our box.
		void Clear(int r, bool window = true) const;

		// Return:	true if the cursor is visible right now or false if it's not.
		bool CursorIsOn(void) const;

		// Turn on/off the blinkin' cursor.
		//
		// In:	visible		true to make it show or false to hide it.
		void CursorOn(bool visible) const;

		// Find where the cursor is now.
		//
		// Out:	x	The horizontal location (0 -> "Cols()" - 1).
		//		y	The vertical location (0 -> "Rows()" - 1).
		void CP(int &x, int &y) const;

		// Find what client pixel the mouse is hovering over right now, with (0, 0) being the upper-left corner.
		//
		// Out:	x	The horizontal location.
		//		y	The vertical location.
		//
		// Return:	false if the mouse is outside our window.
		bool MPAbs(int &x, int &y) const;

		// Find where the mouse is now.
		//
		// Out:	x	The column (0 -> "Cols()" - 1, usually).
		//		y	The row    (0 -> "Rows()" - 1, usually).
		//
		// Return:	false if the mouse is outside our window ("x" and "y" should be used for relative, not absolute, positioning).
		bool MP(int &x, int &y) const;

		// Place the cursor at a specific spot on the screen.
		//
		// In:	y	The vertical location (0 -> "Rows()" - 1).
		//		x	The horizontal location (0 -> "Cols()" - 1).
		void Goto(int y = 0, int x = 0) const;

		// Turn End-o'-Line (EOL) wrapping on or off.  This can be used to keep the display from
		//	moving up a line when a character is written in the lower-right hand corner of the
		//	window.
		//
		// In:	on	true to enable scrolling (the default) or false to disable it.
		//
		// Note:	Turn this back ON before getting any input!!
		void EOLWrap(bool on = true) const;

		// See if a given key is being pressed or not.
		//
		// In:	vKey	Specifies one of 256 possible virtual-key codes.  For more information, see Virtual-Key Codes in the Help.
		//
		// Return:	true if that key is down right now.
		bool keyDown(int vKey) const;

		// See if a given key has just been pressed.
		//
		// In:	vKey	Specifies one of 256 possible virtual-key codes.  For more information, see Virtual-Key Codes in the Help.
		//
		// Return:	true if that key's been pressed since last we checked.  This may not always work properly - see the Help on GetAsyncKeyState.
		bool keyPressed(int vKey) const;

		// Consume everything in our input buffer.
		void flushKeys() const;

		// Change our window's title.
		//
		// In:	s	The text to display.
		void Title(const wchar_t *s) const;

		// Copy a section of the window somewhere else.
		//
		// In:	sleft		The left coordinate of the area to scroll (0 -> "Cols()" - 1).
		//		stop		The top coordinate of the area to scroll (0 -> "Rows()" - 1).
		//		sright		The right coordinate of the area to scroll (0 -> "Cols()" - 1).
		//		sbottom		The bottom coordinate of the area to scroll (0 -> "Rows()" - 1).
		//		dx			The left coordinate of the destination (0 -> "Cols()" - 1).
		//		dy			The top coordinate of the destination (0 -> "Rows()" - 1).
		void Scroll(int sleft, int stop, int sright, int sbottom, int dx, int dy) const;
		void Scroll(int sleft, int stop) const
		{
			Scroll(sleft, stop, cols - 1, rows - 1, 0, 0);
		}

		// Adjust the window dimensions.
		//
		// In:	width	The desired number o' columns (1+, 0 for max possible).
		//		height	The desired number o' rows (1+, 0 for max possible).
		//		pos		true to maximize and center the window.
		//		fs		true to go full screen.
		//
		// Note:	You may not get the size you want and this resets any internal window to the full
		//				screen.
		void Size(int width = 80, int height = 25, bool pos = true, bool fs = false);

		// Create a "separate" box within our screen.
		//
		// In:	left	The left coordinate of the area (0 -> "Cols()" - 1).
		//		top		The top coordinate of the area (0 -> "Rows()" - 1).
		//		right	The right coordinate of the area (0 -> "Cols()" - 1).
		//		bottom	The bottom coordinate of the area (0 -> "Rows()" - 1).
		//
		// Note:	Letting lines wrap without explicit newlines and/or getting input with cin can
		//				mess the window up!
		void Window(int left, int top, int right, int bottom);
		void Window()
		{
			Window(0, 0, cols - 1, rows - 1);
		}

		// Return:	Our current fore/background colors & more.
		Attr getAttr() const { return this->attrs; }

		// Turn on/off the mouse cursor.
		//
		// In:	visible		true to make it show or false to hide it.
		//
		// Note:	This only works in full screen mode and then only to ditch the cursor...
		void MouseOn(bool visible) const;

		// Return:	true if we are currently back-buffering.
		bool getBB() const { return this->bb; }

		// Change whether or not we're back-buffering the screen.
		//
		// In:	bb	true if we should back-buffer to reduce flicker or false to skip it and save memory instead.
		void setBB(bool bb);

		// Flip the back-buffer, if we've got one, so we see it on the screen.
		void Flip();

		// Display an Image.
		//
		// In:	i	The picture to print.
		//		x	The column for its upper-left cell.
		//		y	The row for its upper-left cell.
		//
		// Note:	No error checking is done on the coordinates!
		void show(const Image &i, int x, int y) const;

		// Return:	Do we bother to WaitForVerticalBlank()?
		bool getW4VB() const { return this->w4VB; }
		// Alter whether or not we delay for WaitForVerticalBlank().
		//
		// In:	w4VB	true to make windowed mode smoother but slower.
		void setW4VB(bool w4VB) { this->w4VB = w4VB; }

		// Change the output's default character attributes.
		//
		// In:	l	The stream to alter.
		//		a	The new values to use.
		//
		// Return:	The stream "l".
		Output & setAttr(Output &l, const Attr &a);

		// Display a string without looking for any special formatting characters.
		//
		// In:	s	The text to show.
		void putRawString(const std::wstring &s) const;

		// All the carefully-watched forms o' output.
		//
		// In:	???	What to show.
		//
		// Return:	Us.
#define INSERTION(pt) Console & operator <<(pt);
		INSERTION(char)
		INSERTION(unsigned char)
		INSERTION(signed char)
		INSERTION(wchar_t)
		INSERTION(const char *);
		INSERTION(const unsigned char *)
		INSERTION(const signed char *)
		INSERTION(const wchar_t *)
		INSERTION(short)
		INSERTION(unsigned short)
		INSERTION(int)
		INSERTION(unsigned int)
		INSERTION(long)
		INSERTION(unsigned long)
		INSERTION(long long)
		INSERTION(unsigned long long)
		INSERTION(float)
		INSERTION(double)
		INSERTION(long double)
		INSERTION(const void *)
		INSERTION(const std::string &)
		INSERTION(const std::wstring &)
		INSERTION(OutputPF const &)
		INSERTION(std::ios_base & (* const)(std::ios_base &));
		template<class _Elem> inline
		Console & operator<<(const std::_Fillobj<_Elem>& _Manip)
		{	// set fill character in output stream
			this->fill(_Manip._Fill);
			return (*this);
		}
		template<class _Arg> inline
		Console & operator <<(const std::_Smanip<_Arg>& _Manip)
		{	// insert by calling function with output stream and argument
			(*_Manip._Pfun)(*this, _Manip._Manarg);
			return (*this);
		}
};

// The one-and-only!
extern Console &con;

// Handy "manipulators".
#define COLOR(fn, attr) inline Output & fn(Output &o) { return con.setAttr(o, attr); }
COLOR(Def, DEF)
COLOR(Blackout, BLACKOUT)
COLOR(DarkRed, DARKRED)
COLOR(DarkGreen, DARKGREEN)
COLOR(DarkBlue, DARKBLUE)
COLOR(DarkYellow, DARKYELLOW)
COLOR(DarkMagenta, DARKMAGENTA)
COLOR(DarkCyan, DARKCYAN)
COLOR(LightGray, LIGHTGRAY)
COLOR(DarkGray, DARKGRAY)
COLOR(Red, RED)
COLOR(Green, GREEN)
COLOR(Blue, BLUE)
COLOR(Yellow, YELLOW)
COLOR(Magenta, MAGENTA)
COLOR(Cyan, CYAN)
COLOR(White, WHITE)
COLOR(BGDarkRed, BGDARKRED)
COLOR(BGDarkGreen, BGDARKGREEN)
COLOR(BGDarkBlue, BGDARKBLUE)
COLOR(BGDarkYellow, BGDARKYELLOW)
COLOR(BGDarkMagenta, BGDARKMAGENTA)
COLOR(BGDarkCyan, BGDARKCYAN)
COLOR(BGLightGray, BGLIGHTGRAY)
COLOR(BGDarkGray, BGDARKGRAY)
COLOR(BGRed, BGRED)
COLOR(BGGreen, BGGREEN)
COLOR(BGBlue, BGBLUE)
COLOR(BGYellow, BGYELLOW)
COLOR(BGMagenta, BGMAGENTA)
COLOR(BGCyan, BGCYAN)
COLOR(BGWhite, BGWHITE)

} // namespace FS

#endif

console.cpp
CPP / C++ / C Code:
// Console.cpp : Add support for some interesting console tricks.

#include <iostream>
#include <fstream>

#include "Console.h"

// For WaitForVerticalBlank().
#define INITGUID
#include <ddraw.h>
#define DDOBJECT reinterpret_cast<IDirectDraw7 *>(DDobject)

namespace FS
{

// Handy built-in colors for all to use.
const Attr
DEF				= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
BLACKOUT		= 0,
DARKRED			= FOREGROUND_RED,
DARKGREEN		= FOREGROUND_GREEN,
DARKBLUE		= FOREGROUND_BLUE,
DARKYELLOW		= FOREGROUND_RED | FOREGROUND_GREEN,
DARKMAGENTA		= FOREGROUND_RED | FOREGROUND_BLUE,
DARKCYAN		= FOREGROUND_GREEN | FOREGROUND_BLUE,
LIGHTGRAY		= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
DARKGRAY		= FOREGROUND_INTENSITY,
RED				= FOREGROUND_RED | FOREGROUND_INTENSITY,
GREEN			= FOREGROUND_GREEN | FOREGROUND_INTENSITY,
BLUE			= FOREGROUND_BLUE | FOREGROUND_INTENSITY,
YELLOW			= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
MAGENTA			= FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
CYAN			= FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
WHITE			= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
BGDARKRED		= BACKGROUND_RED,
BGDARKGREEN		= BACKGROUND_GREEN,
BGDARKBLUE		= BACKGROUND_BLUE,
BGDARKYELLOW	= BACKGROUND_RED | BACKGROUND_GREEN,
BGDARKMAGENTA	= BACKGROUND_RED | BACKGROUND_BLUE,
BGDARKCYAN		= BACKGROUND_GREEN | BACKGROUND_BLUE,
BGLIGHTGRAY		= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
BGDARKGRAY		= BACKGROUND_INTENSITY,
BGRED			= BACKGROUND_RED | BACKGROUND_INTENSITY,
BGGREEN			= BACKGROUND_GREEN | BACKGROUND_INTENSITY,
BGBLUE			= BACKGROUND_BLUE | BACKGROUND_INTENSITY,
BGYELLOW		= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY,
BGMAGENTA		= BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY,
BGCYAN			= BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY,
BGWHITE			= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;

/***********/
/* Globals */
/***********/

// The one-and-only!
Console &con = Console::GetTheOnlyInstance();

/***********/
/* Private */
/***********/

// Default constructor.
Console::Console() : Output(std::cout.rdbuf(), true)
{
	// Where our standard output goes.
	out = GetStdHandle(STD_OUTPUT_HANDLE);
	vis = out; // You da man.
	// Where our standard input comes from.
	in = GetStdHandle(STD_INPUT_HANDLE);

	// Use the current dimensions.
	CONSOLE_SCREEN_BUFFER_INFO info;
	GetConsoleScreenBufferInfo(out, &info);
	cols = info.dwSize.X;
	rows = info.dwSize.Y;
	Window();

	// Get what the attributes are.
	attrs = info.wAttributes;

	// Only one screen for now.
	bb = false;

	// Who are we?
	hwnd = GetConsoleWindow();

	// Stay smooth even in windowed mode.
	WCHAR wszPath[MAX_PATH] = { 0 };
	::GetSystemDirectory(wszPath, MAX_PATH);
	std::wstring path(wszPath);
	path += L"\\ddraw.dll";
	ddrawLib = LoadLibraryW(path.c_str());
	DDobject = 0; // In case we fail.
	if (ddrawLib)
	{
		// Nasty-lookin' pointer-to-function:
		typedef HRESULT (WINAPI *pf)(GUID *, void **, REFIID, IUnknown *);
		pf _DirectDrawCreateEx = reinterpret_cast<pf>(GetProcAddress(ddrawLib, "DirectDrawCreateEx"));
		if (_DirectDrawCreateEx)
		{
			if (SUCCEEDED(_DirectDrawCreateEx(NULL, reinterpret_cast<void **>(&DDobject), IID_IDirectDraw7, NULL)))
				// Not sure if this is necessary but what the heck.
				DDOBJECT->SetCooperativeLevel(NULL, DDSCL_NORMAL);
		}
	}
	w4VB = true;
}

// Return:	true if the standard output screen buffer is currently visible.
bool Console::StdIsVis() const
{
	return GetStdHandle(STD_OUTPUT_HANDLE) == vis;
}

// Perform a "safe" newline, i.e., one which preserves our colors.
void Console::nl(void) const
{
	// Where are we?
	CONSOLE_SCREEN_BUFFER_INFO info;
	GetConsoleScreenBufferInfo(out, &info);

	// Go to the start of the next row.
	++info.dwCursorPosition.Y;
	info.dwCursorPosition.X = (info.dwCursorPosition.Y >= wtop && info.dwCursorPosition.Y <= wbottom + 1)
		? wleft : 0;
	if (info.dwCursorPosition.Y == wbottom + 1 || info.dwCursorPosition.Y == rows)
	{
		// Stay on the last line and shift everything up one.
		if (--info.dwCursorPosition.Y == wbottom)
			// Just our box.
			Scroll(wleft, wtop + 1, wright, wbottom, wleft, wtop);
		else
			// The entire window.
			Scroll(0, 1);
	}
	SetConsoleCursorPosition(out, info.dwCursorPosition);
}

// Make sure a box's dimensions make sense.
//
// I/O:	left	The left coordinate of the area (l -> r, <= right).
//		top		The top coordinate of the area (t -> b, <= bottom).
//		right	The right coordinate of the area (l -> r, >= left).
//		bottom	The bottom coordinate of the area (t -> b, >= top).
//
// In:	l, t, r, b	Acceptable left, top, right and bottom coordinates.
void Console::BoxCheck(int &left, int &top, int &right, int &bottom,
	int l, int t, int r, int b) const
{
	// Bounds-check...
	if (left	< l) left	= l;
	if (top		< t) top	= t;
	if (right	> r) right	= r;
	if (bottom	> b) bottom	= b;

	// Extra paranoia.
	if (right < left) right = left;
	if (bottom < top) bottom = top;
}

// What are the dimensions of our client area, in pixels?
//
// Out:	width	How wide we are.
//		height	How tall we are.
//
// Return:	true if we're windowed, false if full screen.
bool Console::getClientDim(int &width, int &height) const
{
	RECT c;
	GetClientRect(hwnd, &c);
	bool fullscreen = 0 == c.bottom && 0 == c.left && 0 == c.right && 0 == c.top; // Probably imperfect check for full screen.
	if (fullscreen)
	{
		// What's the current rez?
		c.right  = GetSystemMetrics(SM_CXSCREEN);
		c.bottom = GetSystemMetrics(SM_CYSCREEN);
	}
	width  = c.right;
	height = c.bottom;
	return !fullscreen;
}

/**********/
/* Public */
/**********/

// Destructor.
Console::~Console(void)
{
	// Free the extra buffer if we've got it.
	this->setBB(false);

	// DirectX.
	if (DDobject)
		DDOBJECT->Release();
	if (ddrawLib)
        FreeLibrary(ddrawLib);
}

// Clear the entire screen or just our limited window.  This leaves the cursor in the
//	upper-left corner o' whatever area it just wiped.
//
// In:	window	true to limit ourselves to our box.
void Console::Clear(bool window) const
{
	// What's the extent?
	int	t = (!window) ? 0	 : wtop,
		b = (!window) ? rows : wbottom + 1;

	// Do the selected rows.
	for (int r = t; r < b; r++)
		Clear(r, window);

	// Where do we go from here?
	if (window)
		Goto(wtop, wleft);
	else
		Goto();
}

// Clear a line.  The cursor doesn't move.
//
// In:	r		The row to wipe (0 -> "Rows()" - 1).
//		window	true to limit ourselves to our box.
void Console::Clear(int r, bool window) const
{
	if (r < 0 || r >= rows)
		// Nope.
		return;

	// Buh-bye.
	DWORD len = (!window) ? cols : wright - wleft + 1, num;
	COORD c	  = { (window && r >= wtop && r <= wbottom) ? wleft : 0, r, };
	FillConsoleOutputAttribute(out, attrs, len, c, &num);
	FillConsoleOutputCharacter(out, ' ',   len, c, &num);
}

// Return:	true if the cursor is visible right now or false if it's not.
bool Console::CursorIsOn(void) const
{
	CONSOLE_CURSOR_INFO curs;
	GetConsoleCursorInfo(out, &curs);
	return ((curs.bVisible == TRUE) ? true : false);
}

// Turn on/off the blinkin' cursor.
//
// In:	visible		true to make it show or false to hide it.
void Console::CursorOn(bool visible) const
{
	CONSOLE_CURSOR_INFO curs;
	GetConsoleCursorInfo(out, &curs);
	if (curs.bVisible == TRUE && visible || curs.bVisible == FALSE && !visible)
		// We're already the way they want it.
		return;

	// Change it.
	curs.bVisible = (visible) ? TRUE : FALSE;
	SetConsoleCursorInfo(out, &curs);
}

// Find where the cursor is now.
//
// Out:	x	The horizontal location (0 -> "Cols()" - 1).
//		y	The vertical location (0 -> "Rows()" - 1).
void Console::CP(int &x, int &y) const
{
	// Where are you?
	CONSOLE_SCREEN_BUFFER_INFO info;
	GetConsoleScreenBufferInfo(out, &info);
	x = info.dwCursorPosition.X;
	y = info.dwCursorPosition.Y;
}

// Find what client pixel the mouse is hovering over right now, with (0, 0) being the upper-left corner.
//
// Out:	x	The horizontal location.
//		y	The vertical location.
//
// Return:	false if the mouse is outside our window.
bool Console::MPAbs(int &x, int &y) const
{
	// Where is it in screen coords?
	POINT p;
	GetCursorPos(&p);

	// Translate to our window, if needed.
	int width, height;
	bool fullscreen = !getClientDim(width, height);
	if (!fullscreen)
		ScreenToClient(hwnd, &p);

	// Here ya' go:
	x = p.x; y = p.y;
	return fullscreen ? true : !(x < 0 || y < 0 || x >= width || y >= height);
}

// Find where the mouse is now.
//
// Out:	x	The column (0 -> "Cols()" - 1, usually).
//		y	The row    (0 -> "Rows()" - 1, usually).
//
// Return:	false if the mouse is outside our window ("x" and "y" should be used for relative, not absolute, positioning).
bool Console::MP(int &x, int &y) const
{
	// Where are we in relation to our client area?
	bool inside = MPAbs(x, y);

	// Map that to a row and column based on our dimensions.
	int width, height;
	getClientDim(width, height);
	x = static_cast<int>(x / static_cast<double>(width)  * cols);
	y = static_cast<int>(y / static_cast<double>(height) * rows);

	// The final summary:
	return inside;
}

// Place the cursor at a specific spot on the screen.
//
// In:	y	The vertical location (0 -> "Rows()" - 1).
//		x	The horizontal location (0 -> "Cols()" - 1).
void Console::Goto(int y, int x) const
{
	// Keep within acceptable bounds.
	x = max(x, 0);
	x = min(x, cols - 1);
	y = max(y, 0);
	y = min(y, rows - 1);

	// Make it so.
	COORD cp = { x, y, };
	SetConsoleCursorPosition(out, cp);
}

// Turn End-o'-Line (EOL) wrapping on or off.  This can be used to keep the display from moving
//	up a line when a character is written in the lower-right hand corner of the window.
//
// In:	on	true to enable scrolling (the default) or false to disable it.
//
// Note:	Turn this back ON before getting any input!!
void Console::EOLWrap(bool on) const
{
	// How are we now?
	DWORD mode;
	GetConsoleMode(out, &mode);
	if (on)
		// Turn it on.
		mode |= ENABLE_WRAP_AT_EOL_OUTPUT;
	else
		// Turn it off.
		mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
	SetConsoleMode(out, mode);
}

// See if a given key is being pressed or not.
//
// In:	vKey	Specifies one of 256 possible virtual-key codes.  For more information, see Virtual-Key Codes in the Help.
//
// Return:	true if that key is down right now.
bool Console::keyDown(int vKey) const
{
	bool down = 0 != (GetAsyncKeyState(vKey) & 0x8000); // Test that high bit.
	FlushConsoleInputBuffer(in); // Don't let cin see it!
	return down;
}

// See if a given key has just been pressed.
//
// In:	vKey	Specifies one of 256 possible virtual-key codes.  For more information, see Virtual-Key Codes in the Help.
//
// Return:	true if that key's been pressed since last we checked.  This may not always work properly - see the Help on GetAsyncKeyState.
bool Console::keyPressed(int vKey) const
{
	bool down = 0 != (GetAsyncKeyState(vKey) & 0x0001); // Test that low bit.
	FlushConsoleInputBuffer(in); // Don't let cin see it!
	return down;
}

// Consume everything in our input buffer.
void Console::flushKeys() const
{
	// Check 'em all.
	for (int i = 0; i < 256; i++)
		GetAsyncKeyState(i);
	FlushConsoleInputBuffer(in); // Don't let cin see 'em!
}

// Change our window's title.
//
// In:	s	The text to display.
void Console::Title(const wchar_t *s) const
{
	SetConsoleTitle(s);
}

// Copy a section of the window somewhere else.
//
// In:	sleft		The left coordinate of the area to scroll (0 -> "Cols()" - 1).
//		stop		The top coordinate of the area to scroll (0 -> "Rows()" - 1).
//		sright		The right coordinate of the area to scroll (0 -> "Cols()" - 1).
//		sbottom		The bottom coordinate of the area to scroll (0 -> "Rows()" - 1).
//		dx			The left coordinate of the destination (0 -> "Cols()" - 1).
//		dy			The top coordinate of the destination (0 -> "Rows()" - 1).
void Console::Scroll(int sleft, int stop, int sright, int sbottom, int dx, int dy) const
{
	// Bounds-check...
	BoxCheck(sleft, stop, sright, sbottom);
	if (dx <	0)		dx = 0;
	if (dx >=	cols)	dx = cols - 1;
	if (dy <	0)		dy = 0;
	if (dy >=	rows)	dy = rows - 1;

	// Git ready!
	SMALL_RECT	src		= { sleft, stop, sright, sbottom, };
	COORD		dest	= { dx, dy, };
	CHAR_INFO	fill	= { ' ', attrs, };

	// Make it so.
	ScrollConsoleScreenBuffer(out, &src, NULL, dest, &fill);
}

// Adjust the window dimensions.
//
// In:	width	The desired number o' columns (1+, 0 for max possible).
//		height	The desired number o' rows (1+, 0 for max possible).
//		pos		true to maximize and center the window.
//		fs		true to go full screen.
//
// Note:	You may not get the size you want and this resets any internal window to the full
//				screen.
void Console::Size(int width, int height, bool pos, bool fs)
{
	// They don't need to see this...
	ShowWindow(hwnd, SW_HIDE);

	// How high can we go?
	COORD c = GetLargestConsoleWindowSize(out);
	if (width  < 1 || width  > c.X)	width  = c.X;
	if (height < 1 || height > c.Y)	height = c.Y;

	// Don't want no scroll bars!
	SMALL_RECT dim = { 0, 0, width - 1, height - 1 };
	SetConsoleWindowInfo(out, TRUE, &dim);

	// Now for the buffer.
	c.X = width; c.Y = height;
	SetConsoleScreenBufferSize(out, c);

	// How'd we do?
	CONSOLE_SCREEN_BUFFER_INFO info;
	GetConsoleScreenBufferInfo(out, &info);
	cols = info.dwSize.X;
	rows = info.dwSize.Y;
	Window();

	if (pos)
	{
		// Time to git big!
		SendMessage(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);

		// How large are we and the entire screen?
		RECT rect;
		GetWindowRect(hwnd, &rect);
		int	w  = rect.right - rect.left,
			h  = rect.bottom - rect.top,
			sw = GetSystemMetrics(SM_CXSCREEN),
			sh = GetSystemMetrics(SM_CYSCREEN);

		// Center us.
		MoveWindow(hwnd, (sw - w) >> 1, (sh - h) >> 1, w, h, TRUE);
	}

	if (fs)
	{
		// BEFORE simulating Alt+Enter, be sure
		//	the Ctrl key is up.  Otherwise the
		//	system sees Ctrl+Alt+Enter and won't
		//	go full screen.  The Ctrl key is
		//	probably being held down right now
		//	because we usually start running our
		//	programs with Ctrl+F5.
		//
		// fixed by Lari Norri & Darryl Malcomb,(Darryl)
		while (GetAsyncKeyState(VK_CONTROL)) { }

		// Simulate Alt+Enter.
		SendMessage(hwnd, WM_SYSKEYDOWN, VK_RETURN, 0x20000000);
	}

	// Here we are!
	ShowWindow(hwnd, SW_SHOW);
}

// Create a "separate" box within our screen.
//
// In:	left	The left coordinate of the area (0 -> "Cols()" - 1).
//		top		The top coordinate of the area (0 -> "Rows()" - 1).
//		right	The right coordinate of the area (0 -> "Cols()" - 1).
//		bottom	The bottom coordinate of the area (0 -> "Rows()" - 1).
//
// Note:	Letting lines wrap without explicit newlines and/or getting input with cin can mess
//				the window up!
void Console::Window(int left, int top, int right, int bottom)
{
	// Bounds-check...
	BoxCheck(left, top, right, bottom);

	// Such a cute little window!
	wleft	= left;
	wtop	= top;
	wright	= right;
	wbottom	= bottom;
}

// Turn on/off the mouse cursor.
//
// In:	visible		true to make it show or false to hide it.
//
// Note:	This only works in full screen mode and then only to ditch the cursor...
void Console::MouseOn(bool visible) const
{
	// How are we now?
	DWORD mode;
	GetConsoleMode(in, &mode);
	if (visible)
		// Turn it on.
		mode |= ENABLE_MOUSE_INPUT;
	else
		// Turn it off.
		mode &= ~ENABLE_MOUSE_INPUT;
	SetConsoleMode(in, mode);
}

// Change whether or not we're back-buffering the screen.
//
// In:	bb	true if we should back-buffer to reduce flicker or false to skip it and save memory instead.
void Console::setBB(bool bb)
{
	if (this->bb == bb)
		// It's the same.
		return;

	if (this->bb)
	{
		// Destroy the back-buffer we've got.
		if (!this->StdIsVis())
		{
			// Clone what's currently showin' to the default.

			// Create a temporary buffer the size of our window.
			COORD bs = { this->cols, this->rows };
			CHAR_INFO *buff = new CHAR_INFO[bs.Y * bs.X];

			// Do the entire window.
			SMALL_RECT rect = { 0, 0, bs.X - 1, bs.Y - 1 };

			// Where to copy in the buffer.
			COORD bc = { 0, 0 };

			// Copy...
			if (ReadConsoleOutput(vis, buff, bs, bc, &rect))
				// ...paste!
				WriteConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE),
					buff, bs, bc, &rect);

			// Big flush!
			delete [] buff;

			// Show the default critter.
			this->Flip();
		}

		// Back to normal.
		CloseHandle(out);
		out = vis;
	}
	else
	{
		// Create a clone.
		if (INVALID_HANDLE_VALUE == (out = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL)))
		{
			// Darn, can't.
			out = vis;
			return;
		}

		// Mimic all our existing settings.
		CONSOLE_CURSOR_INFO curs;
		GetConsoleCursorInfo(vis, &curs);
		SetConsoleCursorInfo(out, &curs);

		DWORD mode;
		GetConsoleMode(vis, &mode);
		SetConsoleMode(out, mode);

		CONSOLE_SCREEN_BUFFER_INFO info;
		GetConsoleScreenBufferInfo(vis, &info);
		SetConsoleCursorPosition(out, info.dwCursorPosition);

		SetConsoleTextAttribute(out, attrs);
	}

	// Make it so.
	this->bb = bb;
}

// Flip the back-buffer, if we've got one, so we see it on the screen.
void Console::Flip()
{
	if (!this->bb)
		// Got none.
		return;

	// Exchange 'em.
	std::swap(out, vis);
	if (w4VB && DDobject)
	{
		int width, height;
		if (getClientDim(width, height))
			// Windowed.
			DDOBJECT->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
	}
	SetConsoleActiveScreenBuffer(vis);
}

// Display an Image.
//
// In:	i	The picture to print.
//		x	The column for its upper-left cell.
//		y	The row for its upper-left cell.
//
// Note:	No error checking is done on the coordinates!
void Console::show(const Image &i, int x, int y) const
{
	if (!i.good())
		// Sorry Charlie.
		return;

	// What are its dimensions?
	COORD coordBufSize = { i.getCols(), i.getRows() };

	// Assume they want to start displaying beginning at the upper-left cell.
	COORD coordBufCoord = { 0, 0 };
 
    // Where are we writing to?
	SMALL_RECT srctWriteRect = { x, y, x + coordBufSize.X - 1, y + coordBufSize.Y - 1 };

    // Blit it!
	WriteConsoleOutput(out, i.getChiBuffer(), coordBufSize, coordBufCoord, &srctWriteRect);
}

// Change the output's default character attributes.
//
// In:	l	The stream to alter.
//		a	The new values to use.
//
// Return:	The stream "l".
Output & Console::setAttr(Output &l, const Attr &a)
{
	// Retrieve what we need.
	Attr attr = a;

	if (attr & 0xFF)
	{
		// Bits that determine the foreground and background colors.
		const Attr FG = 0xF, BG = 0xF0;
		if (attr & FG)
			// Replace the current foreground.
			this->attrs &= ~FG;
		if (attr & BG)
			// Replace the current background.
			this->attrs &= ~BG;
		this->attrs |= attr;
	}
	else
		// Black - turn all the bits off.
		this->attrs = attr;
	SetConsoleTextAttribute(this->out, this->attrs);

	// Here we are:
	return l;
}

// Display a string without looking for any special formatting characters.
//
// In:	s	The text to show.
void Console::putRawString(const std::wstring &s) const
{
	DWORD dummy;
	WriteConsole(out, s.c_str(), static_cast<DWORD>(s.size()), &dummy, NULL);
}

// All the carefully-watched forms o' output.
//
// In:	???	What to show.
//
// Return:	Us.
#define INSERTIONED(pt)					\
Console & Console::operator <<(pt p)	\
{										\
	this->T2String(p);					\
	return *this;						\
}
INSERTIONED(char)
INSERTIONED(unsigned char)
INSERTIONED(signed char)
INSERTIONED(wchar_t)
INSERTIONED(const char *);
INSERTIONED(const unsigned char *)
INSERTIONED(const signed char *)
INSERTIONED(const wchar_t *)
INSERTIONED(short)
INSERTIONED(unsigned short)
INSERTIONED(int)
INSERTIONED(unsigned int)
INSERTIONED(long)
INSERTIONED(unsigned long)
INSERTIONED(long long)
INSERTIONED(unsigned long long)
INSERTIONED(float)
INSERTIONED(double)
INSERTIONED(long double)
INSERTIONED(const void *)
Console & Console::operator <<(const std::string &s)
{
	return *this << s.c_str();
}
INSERTIONED(const std::wstring &)
Console & Console::operator <<(OutputPF const &pf)
{
	pf(*this);
	return *this;
}
Console & Console::operator <<(std::ios_base & (* const pf)(std::ios_base &))
{
	pf(*this);
	return *this;
}

/***********/
/* Private */
/***********/

// Efficiently procure space for our dynamic memory.
//
// In:	cols	The number of columns we'll have.
//		rows	The number of rows we'll have.
void Console::Image::reallocate(int cols, int rows)
{
	// If our size is the same don't fragment the heap.
	if (cols * rows != this->cols * this->rows)
	{
		// Out with the old!
		this->free();

		// In with the new!!
		this->cols = cols;
		this->rows = rows;
		this->chiBuffer = new CHAR_INFO[this->cols * this->rows];
	}
}

// Deep duplicate a CHAR_INFO array.
//
// In:	cols	The number of columns we'll have.
//		rows	The number of rows we'll have.
//		ci		A CHAR_INFO for each cell (cols * rows).
void Console::Image::DeepCopy(int cols, int rows, CHAR_INFO const ci[])
{
	reallocate(cols, rows);
	rsize_t num = this->cols * this->rows * sizeof CHAR_INFO;
	memcpy_s(this->chiBuffer, num, ci, num);
}

/**********/
/* Public */
/**********/

// Create a 2D picture.
//
// In:	img		An array of strings containing the characters to display.
//		rows	The height of "img" (1+).  The width is assumed to be the length of the first string and should be the same for all the strings, i.e., the picture
//					is rectangular.
//		attr	Character attributes to use for every cell.  Color primarily but see the CHAR_INFO Help for more options.
Console::Image::Image(const wchar_t * const img[], int rows, Attr attr)
{
	this->clear();
	this->set(img, rows, attr);
}

// Create a 2D picture.
//
// In:	cols	How many columns each row has (1+).
//		rows	How many rows it has          (1+).
//		ci		A CHAR_INFO for each cell	  (rows * cols).
Console::Image::Image(int cols, int rows, CHAR_INFO const ci[])
{
	this->clear();
	this->set(cols, rows, ci);
}

// Create a 2D picture.
//
// In:	fileName	Where to get our information from.
Console::Image::Image(std::string const &fileName) throw(ios_base::failure &, bad_exception &)
{
	this->clear();
	this->Load(fileName);
}

// Copy constructor.
//
// In:	i	An existing one to mimic.
Console::Image::Image(const Image &i)
{
	this->clear();
	this->set(i);
}

// Assignment operator.
//
// In:	i	An existing one to emulate.
Console::Image & Console::Image::operator =(const Image &i)
{
	if (this != &i)
		this->set(i);
	return *this;
}

// Define a 2D picture.
//
// In:	img		An array of strings containing the characters to display.
//		rows	The height of "img" (1+).  The width is assumed to be the length of the first string and should be the same for all the strings, i.e., the picture
//					is rectangular.
//		attr	Character attributes to use for every cell.  Color primarily but see the CHAR_INFO Help for more options.
void Console::Image::set(const wchar_t * const img[], int rows, Attr attr)
{
	if (!img || rows < 1)
		// No sir I don't like it.
		return;

	// What's the width?
	int cols = 0;
	const wchar_t *c = img[0];
	while ('\0' != *c++)
		++cols;
	if (cols < 1)
		// Too thin!
		return;

	// Deep copy!
	reallocate(cols, rows);
	for (int r = 0, i = 0; r < this->rows; r++)
	{
		for (int c = 0; c < this->cols; c++, i++)
		{
			// Use the correct character type in the union.
			this->chiBuffer[i].Char.UnicodeChar	= img[r][c];
			this->chiBuffer[i].Attributes		= attr;
		}
	}
}

// Create a 2D picture.
//
// In:	cols	How many columns each row has (1+).
//		rows	How many rows it has          (1+).
//		ci		A CHAR_INFO for each cell	  (rows * cols).
void Console::Image::set(int cols, int rows, CHAR_INFO const ci[])
{
	if (cols < 1 || rows < 1 || !ci)
		// No sir I don't like it.
		return;

	// I suppose we can trust 'em.
	DeepCopy(cols, rows, ci);
}

// Define a 2D picture.
//
// In:	i	An existing one to clone.
void Console::Image::set(const Image &i)
{
	// I suppose we can trust 'em.
	DeepCopy(i.cols, i.rows, i.chiBuffer);
}

// Get access to one of our rows.
//
// In:	i	The index (0 -=> rows - 1) of the one to retrieve.
//
// Return:	The address of the first CHAR_INFO in the row - use another [] to
//				access a specific column.
#define ARRAY_SUBSCRIPT_OPERATOR				\
	if (i < 0 || i >= this->rows)				\
		throw out_of_range("Invalid index!");	\
	return this->chiBuffer + i * this->cols;
CHAR_INFO * Console::Image::operator [](int i) throw(out_of_range &, bad_exception &)
{
	ARRAY_SUBSCRIPT_OPERATOR
}
// Read-only version for constant objects.
CHAR_INFO const * Console::Image::operator [](int i) const throw(out_of_range &, bad_exception &)
{
	ARRAY_SUBSCRIPT_OPERATOR
}

// Store an Image to a file.
//
// In:	fileName	Where to send our information to.
void Console::Image::Save(std::string const &fileName) const throw(ios_base::failure &, bad_exception &)
{
	std::ofstream ofl;

	// Throw an exception if anything unexpected happens.
	ofl.exceptions(ios_base::badbit | ios_base::eofbit | ios_base::failbit);

	// This will create the file if it doesn't already exist and overwrite it
	//	if it does.
	ofl.open(fileName.c_str(), ios_base::out | ios_base::trunc | ios_base::binary);

	// Store our dimensions.
#define WRITE(var) ofl.write(reinterpret_cast<char const *>(&var), sizeof var);
	WRITE(this->rows)
	WRITE(this->cols)

	// Now for the real data.
	ofl.write(reinterpret_cast<char const *>(this->chiBuffer),
		this->rows * this->cols * sizeof(CHAR_INFO));

	// Finished.
	ofl.close();
}

// Retrieve an Image from a file.
//
// In:	fileName	Where to get our information from.
void Console::Image::Load(std::string const &fileName) throw(ios_base::failure &, bad_exception &)
{
	std::ifstream ifl;

	// Throw an exception if anything unexpected happens.
	ifl.exceptions(ios_base::badbit | ios_base::eofbit | ios_base::failbit);
	try
	{
		ifl.open(fileName.c_str(), ios_base::in | ios_base::binary);

		// Recover our dimensions.
		int rows, cols;
#define READ(var) ifl.read(reinterpret_cast<char *>(&var), sizeof var);
		READ(rows)
		READ(cols)

		// Now for the real data.
		reallocate(cols, rows);
		ifl.read(reinterpret_cast<char *>(this->chiBuffer),
			this->cols * this->rows * sizeof CHAR_INFO);

		// Finished.
		ifl.close();
	}
	catch (ios_base::failure &)
	{
		if (ifl.is_open())
		{
			// We failed somewhere after opening the file so ditch any
			//	partial successes we've had.
			this->free();
			this->clear();
			ifl.close();
		}

		// Let someone above us worry about it some more.
		throw;
	}
}

} // namespace FS

Just be aware that there aren't any problems with the SLList.h, DynArray.h, or Console.h. The first two, while they may not be perfect and possibly might leak a little memory, are from past projects and will work fine for their assigned tasks here. Console.h was created by a past instructor is a re-implementation of parts of iostream and will likely make your head hurt unless your experience is far greater than mine.
Last edited by cable_guy_67 : 18-Aug-2006 at 20:32. Reason: Please surround your C++ code with [cpp] ... [/cpp]
  #2  
Old 18-Aug-2006, 15:51
TurboPT's Avatar
TurboPT TurboPT is offline
Senior Member
 
Join Date: Feb 2006
Location: Atlanta, GA
Posts: 1,233
TurboPT is a jewel in the roughTurboPT is a jewel in the roughTurboPT is a jewel in the rough

Re: need help with a console menu system


Can you add the supporting header files, specifically:

SLList.h, Console.h, and DynArray.h ?

If any of us try to assist you, we'll need those files.
__________________
Use the force...read the source!!
WYCIWYG -- what you code is what you get!
  #3  
Old 18-Aug-2006, 16:19
BullBuchanan BullBuchanan is offline
New Member
 
Join Date: Aug 2006
Posts: 3
BullBuchanan is on a distinguished road

Re: need help with a console menu system


updated my post
  #4  
Old 19-Aug-2006, 02:11
WaltP's Avatar
WaltP WaltP is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Midwest US
Posts: 3,373
WaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to all

Re: need help with a console menu system


Welcome to GID....

It would help if you'd please read the Guidelines. All you said is you were shot and what you're trying to do. It really helps to know what happens with the code you posted (guideline#2) and post code so it's readable (guideline#1).
__________________

The 3 Laws of the Procrastination Society:
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
  #5  
Old 20-Aug-2006, 10:53
TurboPT's Avatar
TurboPT TurboPT is offline
Senior Member
 
Join Date: Feb 2006
Location: Atlanta, GA
Posts: 1,233
TurboPT is a jewel in the roughTurboPT is a jewel in the roughTurboPT is a jewel in the rough

Re: need help with a console menu system


I'm getting too many errors that I don't have time to resolve. Are there any libraries that need to be linked? (like for the directx stuff?)
__________________
Use the force...read the source!!
WYCIWYG -- what you code is what you get!
  #6  
Old 20-Aug-2006, 13:01
BullBuchanan BullBuchanan is offline
New Member
 
Join Date: Aug 2006
Posts: 3
BullBuchanan is on a distinguished road

Re: need help with a console menu system


Quote:
Originally Posted by TurboPT
I'm getting too many errors that I don't have time to resolve. Are there any libraries that need to be linked? (like for the directx stuff?)

thats weird, shouldnt have gotten any errors, maybe related to console. Doesn't matter though I figured it out at about 5 am and managed to get it working the way it was suppossed to.
  #7  
Old 20-Aug-2006, 14:46
TurboPT's Avatar
TurboPT TurboPT is offline
Senior Member
 
Join Date: Feb 2006
Location: Atlanta, GA
Posts: 1,233
TurboPT is a jewel in the roughTurboPT is a jewel in the roughTurboPT is a jewel in the rough

Re: need help with a console menu system


Yes, most were many in the console area...

but good to hear that it's working now!
__________________
Use the force...read the source!!
WYCIWYG -- what you code is what you get!
 
 

Recent GIDBlogInstall Adobe Flash - Without Administrator Rights by LocalTech

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Shapes Functions Version 2 - Arrays! Cecil C Programming Language 1 09-Jul-2006 20:39
Pass by references? Cecil C Programming Language 4 29-Jun-2006 02:30
Console Based Menu Jimbo17 C++ Forum 4 12-Feb-2006 18:30
Bloodshed Dev C++ Project Options JdS C++ Forum 6 11-Nov-2005 17:23
A Question on Start Menu in Windows System Melvin Lin C++ Forum 8 03-Jul-2005 23:53

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 21:55.


vBulletin, Copyright © 2000 - 2010, Jelsoft Enterprises Ltd.