//This was written by CH_2005
//e-mail: ch_2005@programmer.net
//It requires the Carnegie Mellon Graphics Package for Dev-C++
// http://www-2.cs.cmu.edu/~cm-gfxpkg/index.html
//It was in fact written in Dev-Cpp 4.9.7.0 Which is also open source
// you can get dev-cpp from the internet
#include <iostream>
#include <fstream>
#include <conio.h>
#include <math.h>
#include "CarnegieMellonGraphics.h"
#include "colors.h"
#include <string>
#include <vector>
#include <stdlib.h>
#include <math.h>

using namespace std;




//=========GLOBALS=========

//====Create a new window 700 by 500 in size at 1034,310
Window window(20,20,700,500, "CH's VCpp 2D to 3D Wavefront OBJ Creator");    

//==THIS=TELLS=WHAT=THE=PROGRAM=IS=DOING==
typedef enum {NONE,
              /*FILE*/
              LOAD_2D,          //Loads an image to use as a guide in modling
              WIDTH,            //Changes default width at vert
              SAVE,             //Saves the OBJ model file
              EXIT,             //Makes the program quit
              /*ADD*/
              ADD_VERTS,        //Adds points to the vertex array
              ADD_FACES,        //Adds faces to the face array by clicking verts
              ADD_EDGES,        //Adds edges to the edges arry by clicking verts
              /*MOD*/
              MOVE_VERTS,       //Changes the x/y of a vert by click and drag              
              VERT_WIDTH,       //Changes the width at a vert (z)
              /*DEL*/
              DEL_VERTS,        //Deletes a vert from the model!(if edges|faces)
              DEL_FACES,        //Deletes a face by clicking 3 verts of a face
              DEL_EDGES,        //Deletes an edge by clicking 2 verts of an edge
              /*COLORS*/
              COLORS_VERTS,     //Changes the draw color for verts
              COLORS_FACES,     //Changes the draw color for faces
              COLORS_EDGES,     //Changes the draw color for edges
             }mode;
mode PROG_MODE;

//==MODEL=DATA!
struct vert{ //a vert holds and x,y,z set
    int x;
    int y;
    int z;
    //a pretty constructor for the struct
    vert(int x, int y, int z):x(x),y(y),z(z){};
};
struct face{ //in a face the points are define a triange clockwise
    int vert1;
    int vert2;
    int vert3;
    face(int vert1, int vert2, int vert3):
    vert1(vert1),vert2(vert2),vert3(vert3){};
};
struct model{ //these simpe models have just verts and faces ...
    vector<vert> verts;
    //int num_verts;
    vector<face> faces;
    //int_num_faces;
    int width; //...and a default width to just be used in the editor
    //the constructor only inits the width cuz the verts and faces are not known
    model(int width): width(width) {};
};
model OBJ(50);

//==FONT 
//Set Font and Style    
//Char sizes
const int CHAR_WIDTH = 9;
const int CHAR_HEIGHT = 12;

//Foreground and Background font styles
const Style FORE_FONT_STYLE = Style(Color::BLACK,2);
const Style BACK_FONT_STYLE = Style(Color::WHITE,2);

//Font ttf file for font face
const string FONT_FACE = "C:\\WINDOWS\\FONTS\\OCRAEXT.TTF";
const Font FONT = Font(FONT_FACE,CHAR_HEIGHT);


//==CURSOR
const Style FORE_CURSOR_STYLE = Style(Color::BLACK,3);
const Style BACK_CURSOR_STYLE = Style(Color::WHITE,3);

//==RECTANGLES
struct rect{
    int x1;
    int y1;
    int x2;
    int y2;
    //yay a struct constructor!
    rect(int x1, int y1, int x2, int y2):
    x1(x1), x2(x2), y1(y1), y2(y2) {}
};
//screen areas
//           Area           x1    y1    x2        y2
//           ~~~~           ~~    ~~    ~~        ~~
const rect   CANVAS      (  25,   87,   25+651,   87+276 ); //651x276
const rect   IO_WINDOW   (  25,   399,  25+651,   76+399 ); //651x76
const rect   MENU_RECT   (  376,  27,   376+314,  27+34  );

//Menu button rects
//           Area           x1    y1    x2     y2
//           ~~~~           ~~    ~~    ~~     ~~
const rect   FILE_RECT   (  380,  4,  380+48,  25);
const rect   ADD_RECT    (  436,  4,  436+47,  25);
const rect   MOD_RECT    (  490,  4,  490+51,  25);
const rect   DEL_RECT    (  547,  4,  547+44,  25);
const rect   COLORS_RECT (  596,  4,  596+90,  25);

//SubMenu Button Rects
//           Area               x1    y1     x2      y2
//           ~~~~               ~~    ~~     ~~      ~~
//FILE:
const rect   LOAD_2D_RECT    (  383,  33,  383+86,   54);
const rect   WIDTH_RECT      (  475,  33,  475+98,   54);
const rect   SAVE_RECT       (  579,  33,  579+52,   54);
const rect   EXIT_RECT       (  639,  33,  639+42,   54);
//ADD_DEL_COLORS:
const rect   VERTS_RECT      (  391,  33,  391+58,   54);
const rect   FACES_RECT      (  498,  33,  498+62,   54);
const rect   EDGES_RECT      (  605,  33,  605+65,   54);
//MOD:
const rect   MOVE_VERTS_RECT (  383,  33,  383+113,  54);
const rect   VERT_WIDTH_RECT (  574,  33,  574+110,  54);


//==BUTTONS
struct menu_button{
    rect my_rect;
    bool enabled;
    bool active;
    //yay a constructor!
    menu_button(rect my_rect, bool enabled, bool active):
    my_rect(my_rect),enabled(enabled),active(active){}
};

//==MENU BUTTONS
//           Button           Rect       Enabled   Active
//           ~~~~~~           ~~~~       ~~~~~~~   ~~~~~~
menu_button  FILE_BTN   (   FILE_RECT   ,   1    ,   0    );
menu_button  ADD_BTN    (   ADD_RECT    ,   1    ,   0    );
menu_button  MOD_BTN    (   MOD_RECT    ,   0    ,   0    );
menu_button  DEL_BTN    (   DEL_RECT    ,   0    ,   0    );
menu_button  COLORS_BTN (   COLORS_RECT ,   0    ,   0    );


struct button{
    rect my_rect;
    bool enabled;
    bool visable;
    //yay a constructor!
    button(rect my_rect, bool enabled, bool visable):
    my_rect(my_rect),enabled(enabled),visable(visable){}
};
//==SUBMENU BUTTONS
//           Button                Rect               Enabled   Visable
//           ~~~~~~                ~~~~               ~~~~~~~   ~~~~~~~
//FILE:
button  LOAD_2D_BTN            (   LOAD_2D_RECT      ,   0    ,    0    );
button  WIDTH_BTN              (   WIDTH_RECT        ,   0    ,    0    );
button  SAVE_BTN               (   SAVE_RECT         ,   0    ,    0    );
button  EXIT_BTN               (   EXIT_RECT         ,   0    ,    0    );
//ADD:
button  ADD_VERTS_BTN          (   VERTS_RECT        ,   0    ,    0    );
button  ADD_FACES_BTN          (   FACES_RECT        ,   0    ,    0    );
button  ADD_EDGES_BTN          (   EDGES_RECT        ,   0    ,    0    );
//MOD:
button  MOVE_VERTS_BTN         (   MOVE_VERTS_RECT   ,   0    ,    0    );
button  VERT_WIDTH_BTN         (   VERT_WIDTH_RECT   ,   0    ,    0    );
//DEL:
button  DEL_VERTS_BTN          (   VERTS_RECT        ,   0    ,    0    );
button  DEL_FACES_BTN          (   FACES_RECT        ,   0    ,    0    );
button  DEL_EDGES_BTN          (   EDGES_RECT        ,   0    ,    0    );
//COLORS:
button  COLORS_VERTS_BTN       (   VERTS_RECT        ,   0    ,    0    );
button  COLORS_FACES_BTN       (   FACES_RECT        ,   0    ,    0    );
button  COLORS_EDGES_BTN       (   EDGES_RECT        ,   0    ,    0    );



//==COLOR SCHEME
//     State                         Color         Width
//     ~~~~~                         ~~~~~         ~~~~~
Style ENABLED    = Style(Color::     BLUE        ,   2   );
Style ACTIVE     = Style(Color::     GREEN       ,   2   );
Style HOVER      = Style(Color::     RED         ,   2   );
Style DISABLED   = Style(Color    (128,0,128)    ,   2   );
//     ~~~~~                         ~~~~~         ~~~~~
Style VERT_STYLE = Style(Color::     RED         ,   1   );
Style FACE_STYLE = Style(Color::     GREEN       ,   1   );
Style EDGE_STYLE = Style(Color::     BLUE        ,   3   );

//==IMAGES
//          Name                    Path                                 Type
//          ~~~~                    ~~~~                                 ~~~~
const Image BACKGROUND_IMAGE       ("ch_back.png"             ,Image::   PNG    );
const Image FILE_IMAGE             ("ch_file.png"             ,Image::   PNG    );
const Image ADD_DEL_COLORS_IMAGE   ("ch_add_del_colors.png"   ,Image::   PNG    );
const Image MOD_IMAGE              ("ch_mod.png"              ,Image::   PNG    );
      Image TEMPLATE_IMAGE;
//=========END===GLOBALS=========




//=========FUNCTIONS=========

//==BUTTON FUNCTIONS
//This should handle the border colors for a given button as well as return
//if it was clicked
bool clicked(button &to_check,const MouseEvent &m_event);
bool clicked(menu_button &to_check,const MouseEvent &m_event);
bool clicked(const rect &to_check,const MouseEvent &m_event);
void handle_buttons(const MouseEvent &m_event);

//==MENU=FUNCTIONS
//This takes care of the menus
void handle_menus(const MouseEvent &m_event);
//this activates a menu and deactivates all the others
void activate(menu_button &to_check);

//==DRAW==FUNCTIONS
void draw_model(const model &OBJ);
void draw_vert(const vert &to_draw, const Style &the_style);
void draw_vert(const vector<vert> &verts);
void draw_face(const face &to_draw, const Style &the_style);
void draw_face(const vector<face> &faces);

//==FILE=FUNCTIONS
void save_model(const model &to_save,const string &file_path);

//==MODEL=FUNCTIONS
int get_close_vert(int m_x, int m_y);

//==CLEARING FUNCTIONS
// Function to wait for a mouse click and clear the screen
void WaitNClear();
//clear the window
void clear();
//clear an area
void clear(const rect &to_clear);

//==STRING FUNCTIONS
string input_string(int line_nuber, string prompt);
string mid(string mid_of,int pos,int num_char);
//Output a strng to a given line in the io window:
void output(string message,int line_number);

//=========END====FUNCTIONS=========




//========================MAIN!==========================
int main()
{
    //background:
    window.drawImage(BACKGROUND_IMAGE,0,0);
    
    //init the state of the program
    PROG_MODE = NONE;
    
    //to hold the events in the event loop
    MouseEvent m_event;
    KeyboardEvent k_event;
    
    //other vars:
    int m_x, m_y, i;
    string prompt;
    string answer;
    //for finding close est vert
    int dist,small_dist = 1000 ,vert1,vert2,vert3;
        
    //event loop
    //while((!window.isKeyboardQueueEmpty() && (k_event = window.getKeyboardEvent()) == KeyboardEvent() && !(k_event == KeyboardEvent(NamedKey::ESCAPE))) ^ window.isKeyboardQueueEmpty()){
    while (true) {
        //get mouse event now in loop
        m_event = window.waitForMouseEvent();
        m_x = window.getMouseX();
        m_y = window.getMouseY();
               
        //Take care of menus
        handle_menus(m_event);
        
        //Take care of buttons
        handle_buttons(m_event);
        
        switch(PROG_MODE) {
        case NONE:
            break;
        case LOAD_2D:
            //Clear the IO window
            clear(IO_WINDOW);
            //print the action title
            output("Load 2D Template Image 651x276",1);
            //set the prompt + prompt the user
            prompt = "Enter PNG:";            
            answer = input_string(2,prompt);
            //set the teplate image file name and type and display the template
            TEMPLATE_IMAGE = Image(answer,Image::PNG);
            window.drawImage(TEMPLATE_IMAGE,CANVAS.x1,CANVAS.y1);
            //Set the prog mode back to nothing
            PROG_MODE = NONE;
            //clear the io window again.
            clear(IO_WINDOW);
            break;
        case WIDTH:
            //Clear the IO window
            clear(IO_WINDOW);
            //print the action title
            output("Set Default Model Width (+/- z at each vert)",1);
            //set the prompt + prompt the user
            prompt = "Enter Width:";            
            answer = input_string(2,prompt);
            //set the width
            OBJ.width = atoi(answer.c_str());
            //This is to make the width number updated
            window.drawImage(FILE_IMAGE,MENU_RECT.x1,MENU_RECT.y1);
            char width_str[20];
            _ultoa(OBJ.width,width_str,10);
            window.drawText(FORE_FONT_STYLE,FONT,WIDTH_BTN.my_rect.x1+70,WIDTH_BTN.my_rect.y1+15,width_str);
            //Set the prog mode back to nothing
            PROG_MODE = NONE;
            //clear the io window again.
            clear(IO_WINDOW);
            break;
        case SAVE:
            //Clear the IO window
            clear(IO_WINDOW);
            //print the action title
            output("Save 3D Wavefront Model OBJ File",1);
            //set the prompt + prompt the user
            prompt = "Enter OBJ:";            
            answer = input_string(2,prompt);
            //save the model
            save_model(OBJ,answer);
            //Set the prog mode back to nothing
            PROG_MODE = NONE;
            //clear the io window again.
            clear(IO_WINDOW);
            break;
        case ADD_VERTS:
            if(clicked(CANVAS,m_event)) {
                OBJ.verts.push_back(vert(m_x-CANVAS.x1, m_y-CANVAS.y1, OBJ.width));
                OBJ.verts.push_back(vert(m_x-CANVAS.x1, m_y-CANVAS.y1, (-1)*OBJ.width));
                draw_model(OBJ);
            }
            break;
        case ADD_FACES:
            if(clicked(CANVAS,m_event)) {
                //get vert1 and draw it
                vert1 = get_close_vert(m_x,m_y);
                draw_vert(OBJ.verts[vert1],FACE_STYLE);
                
                //get vert 2...
                m_event = window.waitForMouseEvent();
                m_x = window.getMouseX();
                m_y = window.getMouseY();
                while (!clicked(CANVAS,m_event)) {
                    m_event = window.waitForMouseEvent();
                    m_x = window.getMouseX();
                    m_y = window.getMouseY();
                }
                vert2 = get_close_vert(m_x,m_y);
                //...and draw it
                draw_vert(OBJ.verts[vert2],FACE_STYLE);

                //get vert 3...
                m_event = window.waitForMouseEvent();
                m_x = window.getMouseX();
                m_y = window.getMouseY();
                while (!clicked(CANVAS,m_event)) {
                    m_event = window.waitForMouseEvent();
                    m_x = window.getMouseX();
                    m_y = window.getMouseY();
                }
                vert3 = get_close_vert(m_x,m_y);
                //...and draw it
                draw_vert(OBJ.verts[vert3],FACE_STYLE);
                
                OBJ.faces.push_back(face(vert1,vert2,vert3));
                OBJ.faces.push_back(face(vert3+1,vert2+1,vert1+1));
                
                draw_model(OBJ);
            }
            break;
        case ADD_EDGES:
            if(clicked(CANVAS,m_event)) {
                //get vert1 and draw it
                vert1 = get_close_vert(m_x,m_y);
                draw_vert(OBJ.verts[vert1],EDGE_STYLE);
                
                //get vert 2...
                m_event = window.waitForMouseEvent();
                m_x = window.getMouseX();
                m_y = window.getMouseY();
                while (!clicked(CANVAS,m_event)) {
                    m_event = window.waitForMouseEvent();
                    m_x = window.getMouseX();
                    m_y = window.getMouseY();
                }
                vert2 = get_close_vert(m_x,m_y);
                //...and draw it
                draw_vert(OBJ.verts[vert2],EDGE_STYLE);
                
                OBJ.faces.push_back(face(vert2,vert1,vert2+1));
                OBJ.faces.push_back(face(vert1+1,vert2+1,vert1));
                draw_face(OBJ.faces[OBJ.faces.size()-1],EDGE_STYLE);
                draw_model(OBJ);
            }
            break;
        case EXIT:
            //destruct some stuff
            window.~Window();
            
            FONT.~Font();
            
            BACKGROUND_IMAGE.~Image();
            FILE_IMAGE.~Image();
            ADD_DEL_COLORS_IMAGE.~Image();
            MOD_IMAGE.~Image();
            TEMPLATE_IMAGE.~Image();
                        
            return 0;
            break;
        }
    }
	return 0;
}
//========================END===MAIN!==========================

int get_close_vert(int m_x, int m_y) {
    int close_vert, small_dist = 10000, dist;
    for(int i = 0; i < OBJ.verts.size();i+=2) {
        dist = sqrt(double((OBJ.verts[i].x - (m_x-CANVAS.x1)))*(OBJ.verts[i].x - (m_x-CANVAS.x1)) + (OBJ.verts[i].y - (m_y-CANVAS.y1))*(OBJ.verts[i].y - (m_y-CANVAS.y1)));
        //massive debug output :-)
        /*cout << OBJ.verts[i].x << '\t' << (OBJ.verts[i].x - m_x) << '\t' << (OBJ.verts[i].x - m_x)*(OBJ.verts[i].x - m_x)
             << '\t' << OBJ.verts[i].y << '\t' << (OBJ.verts[i].y - m_y) << '\t' << (OBJ.verts[i].y - m_y)*(OBJ.verts[i].y - m_y)
             << endl << (OBJ.verts[i].x - m_x)*(OBJ.verts[i].x - m_x) + (OBJ.verts[i].y - m_y)*(OBJ.verts[i].y - m_y)
             << '\t' << double((OBJ.verts[i].x - m_x))*(OBJ.verts[i].x - m_x) + (OBJ.verts[i].y - m_y)*(OBJ.verts[i].y - m_y)
             << '\t' << sqrt(double((OBJ.verts[i].x - m_x))*(OBJ.verts[i].x - m_x) + (OBJ.verts[i].y - m_y)*(OBJ.verts[i].y - m_y))
             << endl << endl;*/
        if (dist < small_dist) {
            small_dist = dist;
            close_vert = i;
        }
    }
    return close_vert;
}

void save_model(const model &to_save,const string &file_path) {
    
    ofstream ofile;
    ofile.open(file_path.c_str());
        for(int i = 0; i < to_save.verts.size(); i++)
             ofile << "v " 
                   << to_save.verts[i].x << ' '
                   << to_save.verts[i].y << ' '
                   << to_save.verts[i].z << '\n';
        for(int i = 0; i < to_save.faces.size(); i++)
             ofile << "f " 
                   << to_save.faces[i].vert1+1 << ' '
                   << to_save.faces[i].vert2+1 << ' '
                   << to_save.faces[i].vert3+1 << '\n';
    ofile.close();

}

void draw_model(const model &obj){
    draw_face(obj.faces);
    draw_vert(obj.verts);
}

void draw_face(const vector<face> &faces){
    for(int i = 0; i < faces.size();i++) {
        draw_face(faces[i],FACE_STYLE);
    }
}

void draw_face(const face &to_draw, const Style &the_style) {

    window.drawLine(the_style,OBJ.verts[to_draw.vert1].x+CANVAS.x1,OBJ.verts[to_draw.vert1].y+CANVAS.y1,OBJ.verts[to_draw.vert2].x+CANVAS.x1,OBJ.verts[to_draw.vert2].y+CANVAS.y1);
    window.drawLine(the_style,OBJ.verts[to_draw.vert2].x+CANVAS.x1,OBJ.verts[to_draw.vert2].y+CANVAS.y1,OBJ.verts[to_draw.vert3].x+CANVAS.x1,OBJ.verts[to_draw.vert3].y+CANVAS.y1);
    window.drawLine(the_style,OBJ.verts[to_draw.vert3].x+CANVAS.x1,OBJ.verts[to_draw.vert3].y+CANVAS.y1,OBJ.verts[to_draw.vert1].x+CANVAS.x1,OBJ.verts[to_draw.vert1].y+CANVAS.y1);

}

void draw_vert(const vector<vert> &verts){
    for(int i = 0; i < verts.size();i++) {
        draw_vert(verts[i],VERT_STYLE);
    }
}

void draw_vert(const vert &to_draw, const Style &the_style) {
    window.drawCircleFilled(the_style,to_draw.x+CANVAS.x1,to_draw.y+CANVAS.y1,4);
}

void handle_buttons(const MouseEvent &m_event){
    
    if(LOAD_2D_BTN.visable) if(clicked(LOAD_2D_BTN,m_event)) PROG_MODE = LOAD_2D;
    if(WIDTH_BTN.visable) if(clicked(WIDTH_BTN,m_event)) PROG_MODE = WIDTH;
    if(SAVE_BTN.visable) if(clicked(SAVE_BTN,m_event)) PROG_MODE = SAVE;
    if(EXIT_BTN.visable) if(clicked(EXIT_BTN,m_event)) PROG_MODE = EXIT;
    if(ADD_VERTS_BTN.visable) if(clicked(ADD_VERTS_BTN,m_event)) {
            //Clear the IO window
            clear(IO_WINDOW);
            //print the action title
            output("Add Verticies.",1);            
        PROG_MODE = ADD_VERTS;
    }
    if(ADD_FACES_BTN.visable) if(clicked(ADD_FACES_BTN,m_event)) {
            //Clear the IO window
            clear(IO_WINDOW);
            //print the action title
            output("Add Faces.",1);            
        PROG_MODE = ADD_FACES;
    }
    if(ADD_EDGES_BTN.visable) if(clicked(ADD_EDGES_BTN,m_event)) {
            //Clear the IO window
            clear(IO_WINDOW);
            //print the action title
            output("Add Edges.",1);            
        PROG_MODE = ADD_EDGES;
    }

}

void activate(menu_button &to_activate) {
    //deactivate
    FILE_BTN.active = false; if(FILE_BTN.enabled) window.drawRectangleOutline(ENABLED,FILE_BTN.my_rect.x1,FILE_BTN.my_rect.y1,FILE_BTN.my_rect.x2,FILE_BTN.my_rect.y2); else window.drawRectangleOutline(DISABLED,FILE_BTN.my_rect.x1,FILE_BTN.my_rect.y1,FILE_BTN.my_rect.x2,FILE_BTN.my_rect.y2);
    ADD_BTN.active = false; if(ADD_BTN.enabled) window.drawRectangleOutline(ENABLED,ADD_BTN.my_rect.x1,ADD_BTN.my_rect.y1,ADD_BTN.my_rect.x2,ADD_BTN.my_rect.y2); else window.drawRectangleOutline(DISABLED,ADD_BTN.my_rect.x1,ADD_BTN.my_rect.y1,ADD_BTN.my_rect.x2,ADD_BTN.my_rect.y2);
    MOD_BTN.active = false; if(MOD_BTN.enabled) window.drawRectangleOutline(ENABLED,MOD_BTN.my_rect.x1,MOD_BTN.my_rect.y1,MOD_BTN.my_rect.x2,MOD_BTN.my_rect.y2); else window.drawRectangleOutline(DISABLED,MOD_BTN.my_rect.x1,MOD_BTN.my_rect.y1,MOD_BTN.my_rect.x2,MOD_BTN.my_rect.y2);
    DEL_BTN.active = false; if(DEL_BTN.enabled) window.drawRectangleOutline(ENABLED,DEL_BTN.my_rect.x1,DEL_BTN.my_rect.y1,DEL_BTN.my_rect.x2,DEL_BTN.my_rect.y2); else window.drawRectangleOutline(DISABLED,DEL_BTN.my_rect.x1,DEL_BTN.my_rect.y1,DEL_BTN.my_rect.x2,DEL_BTN.my_rect.y2);
    COLORS_BTN.active = false; if(COLORS_BTN.enabled) window.drawRectangleOutline(ENABLED,COLORS_BTN.my_rect.x1,COLORS_BTN.my_rect.y1,COLORS_BTN.my_rect.x2,COLORS_BTN.my_rect.y2); else window.drawRectangleOutline(DISABLED,COLORS_BTN.my_rect.x1,COLORS_BTN.my_rect.y1,COLORS_BTN.my_rect.x2,COLORS_BTN.my_rect.y2);
    //activate
    to_activate.active = true; window.drawRectangleOutline(ACTIVE,to_activate.my_rect.x1,to_activate.my_rect.y1,to_activate.my_rect.x2,to_activate.my_rect.y2);
    if(FILE_BTN.active) {
        LOAD_2D_BTN.visable = true; WIDTH_BTN.visable = true; SAVE_BTN.visable = true; EXIT_BTN.visable = true;
        LOAD_2D_BTN.enabled = true; WIDTH_BTN.enabled = true; SAVE_BTN.enabled = true; EXIT_BTN.enabled = true;
    }
    else {
        LOAD_2D_BTN.visable = false; WIDTH_BTN.visable = false; SAVE_BTN.visable = false; EXIT_BTN.visable = false;
        LOAD_2D_BTN.enabled = false; WIDTH_BTN.enabled = false; SAVE_BTN.enabled = false; EXIT_BTN.enabled = false;    
    }        
    if(ADD_BTN.active) {
        ADD_VERTS_BTN.visable = true; ADD_FACES_BTN.visable = true; ADD_EDGES_BTN.visable = true;
        ADD_VERTS_BTN.enabled = true; ADD_FACES_BTN.enabled = true; ADD_EDGES_BTN.enabled = true;
    }
    else {
        ADD_VERTS_BTN.visable = false; ADD_FACES_BTN.visable = false; ADD_EDGES_BTN.visable = false;
        ADD_VERTS_BTN.enabled = false; ADD_FACES_BTN.enabled = false; ADD_EDGES_BTN.enabled = false;
    }        
}

void handle_menus(const MouseEvent &m_event) {

        if(clicked(FILE_BTN,m_event)) {
            //cout << "You Clicked FILE!" << endl;
            window.drawImage(FILE_IMAGE,MENU_RECT.x1,MENU_RECT.y1);
            activate(FILE_BTN);
            char width_str[20];
            _ultoa(OBJ.width,width_str,10);
            window.drawText(FORE_FONT_STYLE,FONT,WIDTH_BTN.my_rect.x1+70,WIDTH_BTN.my_rect.y1+15,width_str);
        }
        if(clicked(ADD_BTN,m_event)) {
            //cout << "You Clicked ADD!" << endl;
            window.drawImage(ADD_DEL_COLORS_IMAGE,MENU_RECT.x1,MENU_RECT.y1);
            activate(ADD_BTN);
        }
        if(clicked(MOD_BTN,m_event)) {
            //cout << "You Clicked MOD!" << endl;
            window.drawImage(MOD_IMAGE,MENU_RECT.x1,MENU_RECT.y1);
            activate(MOD_BTN);
        }
        if(clicked(DEL_BTN,m_event)) {
            //cout << "You Clicked DEL!" << endl;
            window.drawImage(ADD_DEL_COLORS_IMAGE,MENU_RECT.x1,MENU_RECT.y1);
            activate(DEL_BTN);
        }
        if(clicked(COLORS_BTN,m_event)) {
            //cout << "You Clicked COLORS!" << endl;
            window.drawImage(ADD_DEL_COLORS_IMAGE,MENU_RECT.x1,MENU_RECT.y1);
            activate(COLORS_BTN);
        }
}

bool clicked(const rect &to_check,const MouseEvent &m_event){

    //m_event = window.waitForMouseEvent();
    int m_x, m_y;
    bool click;
    m_x = window.getMouseX();
    m_y = window.getMouseY();
    click = m_event == MouseEvent(MouseEvent::BUTTON_DOWN_EVENT,MouseEvent::LEFT_BUTTON);
    
    //cout << m_event << '\t' << click << endl;
    
    return (click && m_x >= to_check.x1 && m_x <= to_check.x2 && m_y >= to_check.y1 && m_y <= to_check.y2);
}

bool clicked(menu_button &to_check,const MouseEvent &m_event){

    int m_x, m_y;
    bool click;
    m_x = window.getMouseX();
    m_y = window.getMouseY();
    click = m_event == MouseEvent(MouseEvent::BUTTON_DOWN_EVENT,MouseEvent::LEFT_BUTTON);
    
    //debug output
    //cout << m_event << '\t' << click << endl;
    
    if(to_check.enabled && m_x >= to_check.my_rect.x1 && m_x <= to_check.my_rect.x2 && m_y >= to_check.my_rect.y1 && m_y <= to_check.my_rect.y2){
        //Draw "hover" rectangle around Load2dButton
        if(!to_check.active) window.drawRectangleOutline(HOVER,to_check.my_rect.x1,to_check.my_rect.y1,to_check.my_rect.x2,to_check.my_rect.y2);
        if(click) return true;
    }
    else {
        if(to_check.enabled) {
           //Draw "enabled" rectangle around Load2dButton
           if(!to_check.active) window.drawRectangleOutline(ENABLED,to_check.my_rect.x1,to_check.my_rect.y1,to_check.my_rect.x2,to_check.my_rect.y2);                        
        }
        else {
           //Draw "disabled" rectangle around Load2dButton
           window.drawRectangleOutline(DISABLED,to_check.my_rect.x1,to_check.my_rect.y1,to_check.my_rect.x2,to_check.my_rect.y2);                        
        }
    }
    return false;
}

bool clicked(button &to_check,const MouseEvent &m_event){

    //m_event = window.waitForMouseEvent();
    int m_x, m_y;
    bool click;
    m_x = window.getMouseX();
    m_y = window.getMouseY();
    click = m_event == MouseEvent(MouseEvent::BUTTON_DOWN_EVENT,MouseEvent::LEFT_BUTTON);
    
    //cout << m_event << '\t' << click << endl;
    
    if(to_check.enabled && m_x >= to_check.my_rect.x1 && m_x <= to_check.my_rect.x2 && m_y >= to_check.my_rect.y1 && m_y <= to_check.my_rect.y2){
        //Draw "hover" rectangle around Load2dButton
        window.drawRectangleOutline(HOVER,to_check.my_rect.x1,to_check.my_rect.y1,to_check.my_rect.x2,to_check.my_rect.y2);            
        if(click) return true;
    }
    else {
        if(to_check.enabled) {
           //Draw "enabled" rectangle around Load2dButton
           window.drawRectangleOutline(ENABLED,to_check.my_rect.x1,to_check.my_rect.y1,to_check.my_rect.x2,to_check.my_rect.y2);                        
        }
        else {
           //Draw "disabled" rectangle around Load2dButton
           window.drawRectangleOutline(DISABLED,to_check.my_rect.x1,to_check.my_rect.y1,to_check.my_rect.x2,to_check.my_rect.y2);                        
        }
    }
    return false;
}

string input_string(int line_number, string prompt){
    //Define String to return
    string to_return;
    
    int x = IO_WINDOW.x1 + CHAR_WIDTH;
    int y = IO_WINDOW.y1 + line_number * (CHAR_HEIGHT+3) + 3;
    
    //Output the Prompt
    window.drawText(FORE_FONT_STYLE,FONT,x,y,prompt.c_str());
    
    //get the chars and output them one at a time
    window.flushKeyboardQueue();
    KeyboardEvent key;
    
    //Draw cursor:
    window.drawLine(FORE_CURSOR_STYLE,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length()+CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);
    //wait for char
    key = window.waitForKeyboardEvent();            
    //Erase cursor:
    window.drawLine(BACK_CURSOR_STYLE,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length()+CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);

    //cout << x << endl;
    for (int char_num = 0; KeyboardEvent(NamedKey::ENTER) != key; char_num++){
        //debug output
        //cout << key << endl;
        
        {
            int i;
            for(i=0;i < 128 && key != KeyboardEvent(char(i)); i++);
            //cout << i << endl;
    
            switch (i) {
            case 0x80: //overflow - that is a special - left,right,etc.
            case 0x08: //backspace //disabled
                
                char_num--;
                //Draw cursor:
                window.drawLine(FORE_CURSOR_STYLE,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);
                //Get the next keypress
                window.flushKeyboardQueue();
                //wait for char
                key = window.waitForKeyboardEvent();            
                //Erase cursor:
                window.drawLine(BACK_CURSOR_STYLE,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);

                /*
                char_num--;

                window.drawText(back_font_style,MyFont,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length(),y,&to_return[char_num]);
                
                to_return = mid(to_return,0,to_return.length()-1);
                
                //Draw cursor:
                window.drawLine(fore_cursor_style,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length()+CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);
                //Get the next keypress
                window.flushKeyboardQueue();
                //wait for char
                key = window.waitForKeyboardEvent();            
                //Erase cursor:
                window.drawLine(back_cursor_style,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length()+CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);
                */
                
                break;
            default:
                //concatenation
                to_return += char(i);        
                //debug outut
                //cout << char(i) << "\t" << i << "\t" << char_num << "\t" << to_return << endl;
                //char output
                window.drawText(FORE_FONT_STYLE,FONT,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length(),y,&to_return[char_num]);
                //debug output
                //cout << i << endl;    
        
                //Draw cursor:
                window.drawLine(FORE_CURSOR_STYLE,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);
                //Get the next keypress
                window.flushKeyboardQueue();
                //wait for char
                key = window.waitForKeyboardEvent();            
                //Erase cursor:
                window.drawLine(BACK_CURSOR_STYLE,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + CHAR_WIDTH,y,x + CHAR_WIDTH*prompt.length() + CHAR_WIDTH*to_return.length() + 2*CHAR_WIDTH,y);
        
                break;
            };
        }

    };

    //debug return
    //to_return = "Test abcdef.";    
    return to_return;
}

string mid(string mid_of,int pos,int num_char){

    string to_return;
    
    for (int i = pos; i < pos + num_char; i++)
        to_return += mid_of[i];
    
    return to_return;

}

void WaitNClear()
{ 
    /*//Set position
    int x = IO_WINDOW.x1 + CHAR_WIDTH;
    int y = IO_WINDOW.y1 + 4 * (CHAR_HEIGHT+3) + 10;*/

    //Display Message
	string message;
	message = "Press any key to continue...";
    //window.drawText(FORE_FONT_STYLE,FONT,x,y,message);    
    output(message,1);
    output(message,2);
    output(message,3);
    output(message,4);
    output(message,5);

    //Get keypress
    window.flushKeyboardQueue();
    window.waitForKeyboardEvent();
    
    //Clear screen
    clear();
}

void output(string message,int line_number) {

   //Set position
    int x = IO_WINDOW.x1 + CHAR_WIDTH;
    int y = IO_WINDOW.y1 + line_number * (CHAR_HEIGHT+3) + 3;

    //Display Message
    window.drawText(FORE_FONT_STYLE,FONT,x,y,message);
    
}

void clear() {
    // Draw a rectangle that covers the entire window
    window.drawRectangleFilled(Style::WHITE,0, 0, window.getWidth(), window.getHeight());
}

void clear(const rect &to_clear) {
    window.drawRectangleFilled(BACK_FONT_STYLE,to_clear.x1,to_clear.y1,to_clear.x2,to_clear.y2);
}