/*	figzeich.c -- (c) RTC @ 2003, Programm unter GPL			*/
/*	Benutzer zeichnet Rechtecke, Quadrate, Ellipsen, Kreise oder Linien,	*/
/*	welche er mit der rechten Maustaste farbig füllen kann;			*/
/*	Programm wird mit Tastendruck außer 1/2/3/4/5/6/links/rechts beendet	*/

/* ----------------- Inkludieren der relevanten Headerdateien ----------------- */
#include <time.h>
#include <graphics.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>

/* -------------------------- Konstanten-Definition --------------------------- */
#define MAXX 640
#define MAXY 480


/* ------------------------ Abhandlung des Zeichnens -------------------------- */
int main(int argc, char* argv[]){
	/*	[xy]start sind die Anfangskoordinaten einer Figur,
		[xy]mom sind die momentanen Positionen, wenn die linke Maustaste gedrückt ist,
		[xy]aend sind die veränderten Koordinaten, die ein Neuzeichnen veranlassen
		[xy]max beschreiben die maximale Ausdehnung des Grafikfensters,
		[xy]diff geben die Änderung der Koordinaten zum Startpunkt an und beschreiben
		  bei Ellipse bzw. Kreis den Radius derer,
		figur gibt die zu zeichnende Figur an
			1 = Rechteck (Standard)
			2 = Quadrat
			3 = Ellipse
			4 = Kreis
			5 = Linie
			6 = freie Form
		taste gibt an, welche Taste gedrückt wurde (Standard=Key_1) */
	int xstart, ystart, xmom, ymom, xaend, yaend, xmax, ymax, xdiff=0, ydiff=0, figur=1, taste=Key_1, taste_alt=Key_1;

	/*	erst_figur zeigt an, ob schon eine Figur gezeichnet wurde (0) oder nicht (1),
		erst_right zeigt an, ob die rechte Taste nach einem Zeichnen das erste Mal gedrückt wurde (1) oder nicht (0),
		beenden gibt an, dass eine andere Taste als 1-6/links/rechts gedrückt wurde und beendet die Schleife (1),
		x_groesser zeigt an, dass die Änderung x-seitig größer gleich y-seitig ist (1) oder nicht (0) */
	bool erst_figur=1, erst_right=0, beenden=0, x_groesser=0;

	/* --- Graphen initialisieren, Vorarbeit erledigen --- */
	initgraph(MAXX, MAXY);
	cleardevice(BLACK);
	srand(time(NULL));
	xmax = getmaxx();
	ymax = getmaxy();

	/* --- Rechteck als Rahmen zeichnen --- */
	setcolor(LIGHTGRAY);
	setlinestyle(SOLID_LINE, 1);
	rectangle(0, 0, xmax, ymax);
	mouse_setwindow(1, 1, xmax-1, ymax-1);
	setviewport(1, 1, xmax-1, ymax-1);

	/* --- Begrüßungsmeldung ausgeben mit Beschreibung des Programms --- */
	outtextxy(20, 20, xmax-10, ymax-10,
		"Figuren zeichnen mit der Maus\n"
		"-----------------------------------\n\n"
		"- Figuren werden durch Bewegungen der Maus gezeichnet\n"
		"- mit gedrückter linker Maustaste wird die Figur gezeichnet\n"
		"- mit der rechten Maustaste wird die zuletzt gezeichnete Figur farbig gefüllt\n"
		"- mit der mittleren Maustaste wird der Grafikbildschirm gelöscht\n"
		"- die Figuren wechselt man mit den Zahlentasten 1-6 bzw. den Pfeiltasten links/rechts\n"
		"- folgende Figuren lassen sich zeichnen:\n"
		"  1 = Rechteck (Standard)\n"
		"  2 = Quadrat\n"
		"  3 = Ellipse\n"
		"  4 = Kreis\n"
		"  5 = Linie\n"
		"  6 = freie Form\n\n\n"
		"[ENTER] zum Starten");
	getch();
	clearviewport(BLACK);


	/* --- solange zeichnen, bis nicht auszuwertende Taste betätigt wurde --- */
	while(!beenden){
		/* -- pruefe, welche Taste gedrückt wurde -- */
		if(kbhit()){
			taste=getch();
			/* - nur ausführen, wenn sich die Figur wechselt - */
			if(taste != taste_alt){
				/* Drücken der rechten Maustaste nach Figurwechsel untersagen */
				erst_right=0;

				if(taste == Key_1) figur=1;
					else if(taste == Key_2) figur=2;
				else if(taste == Key_3) figur=3;
				else if(taste == Key_4) figur=4;
				else if(taste == Key_5) figur=5;
				else if(taste == Key_6) figur=6;
				else if(taste == Key_Right)
					if(figur == 6) figur=1;
					else figur++;
				else if(taste == Key_Left)
					if(figur == 1) figur=6;
					else figur--;
				else beenden=1;
				taste_alt=taste;
			}
		}

		/* -- wenn figur=1, dann zeichne Rechteck -- */
		if(figur == 1){
			/* -- zeichne ein gestricheltes Rechteck, wenn die linke Maustaste gedrückt ist --- */
			if(mouse_left()){
				setlinestyle(DASHED_LINE, 1);
				/* - lese die Startkoordinaten des Rechtecks ein - */
				mouse_getpos(&xstart, &ystart);
				/* - elegante Lösung des Überschreibens der alten Figur mit XOR_PUT - */
				setwritemode(XOR_PUT);
				mouse_setcursor(crossCursor);

				/* - lese die momentanen Koordinaten ein und zeichne das Rechteck - */
				while(mouse_left()){
					mouse_getpos(&xmom, &ymom);
					rectangle(xstart, ystart, xmom, ymom);
					xaend = xmom;
					yaend = ymom;

					/* nur ein neues Rechteck zeichnen, wenn die Maus bewegt wurde */
					while(xaend==xmom && yaend==ymom && mouse_left())
						mouse_getpos(&xaend, &yaend);
					rectangle(xstart, ystart, xmom, ymom);
				}
				/* wenn die linke Maustaste los gelassen wurde, dann durchgängiges Rechteck zeichnen */
				/* dabei COPY_PUT verwenden, um das alte Rechteck zu überschreiben */
				setwritemode(COPY_PUT);
				setlinestyle(SOLID_LINE, 1);
				rectangle(xstart, ystart, xmom, ymom);
				erst_figur=0;
				erst_right=1;
				mouse_setcursor(arrowCursor);
			}

			/* -- wenn rechte Maustaste gedrückt, dann mit zufälliger Farbe füllen -- */
			if(mouse_right() && !erst_figur && erst_right){
				erst_right=0;
				setfillstyle(SOLID_FILL, rand()%getmaxcolor());
				bar3d(xstart, ystart, xmom, ymom, 0);
			}
		}

		/* wenn figur=2, dann zeichne Quadrat */
		else if(figur == 2){
			/* -- zeichne ein gestricheltes Quadrat, wenn die linke Maustaste gedrückt ist --- */
			if(mouse_left()){
				setlinestyle(DASHED_LINE, 1);
				mouse_getpos(&xstart, &ystart);
				setwritemode(XOR_PUT);
				mouse_setcursor(crossCursor);

				/* - lese die momentanen Koordinaten ein und zeichne das Quadrat - */
				while(mouse_left()){
					mouse_getpos(&xmom, &ymom);
					/* [xy]diff geben die Veränderung der Mausposition an */
					xdiff=xmom-xstart;
					ydiff=ymom-ystart;
					/* schauen, ob x größer y und somit die Seitenlänge des Quadrats festlegen */
					x_groesser = (abs(xdiff) >= abs(ydiff)) ? 1 : 0;
					if(xdiff < 0 && !(ydiff < 0))
						(x_groesser == 1) ? ymom=ystart-xdiff : xmom=xstart-ydiff;
					else if(ydiff < 0 && !(xdiff < 0))
						(x_groesser == 1) ? ymom=ystart-xdiff : xmom=xstart-ydiff;
					else
						(x_groesser == 1) ? ymom=ystart+xdiff : xmom=xstart+ydiff;

					rectangle(xstart, ystart, xmom, ymom);
					xaend = xmom;
					yaend = ymom;

					/* nur ein neues Quadrat zeichnen, wenn die Maus bewegt wurde */
					while((xaend==xmom || yaend==ymom) && mouse_left())
						mouse_getpos(&xaend, &yaend);
					rectangle(xstart, ystart, xmom, ymom);
				}
				/* wenn die linke Maustaste los gelassen wurde, dann durchgängiges Quadrat zeichnen */
				setwritemode(COPY_PUT);
				setlinestyle(SOLID_LINE, 1);
				rectangle(xstart, ystart, xmom, ymom);
				erst_figur=0;
				erst_right=1;
				mouse_setcursor(arrowCursor);
			}

			/* -- wenn rechte Maustaste gedrückt, dann mit zufälliger Farbe füllen -- */
			if(mouse_right() && !erst_figur && erst_right){
				erst_right=0;
				setfillstyle(SOLID_FILL, rand()%getmaxcolor());
				bar3d(xstart, ystart, xmom, ymom, 0);
			}
		}

		/* wenn figur=3, dann zeichne Ellipse */
		else if(figur == 3){
			/* -- zeichne Ellipse, wenn die linke Maustaste gedrückt ist --- */
			if(mouse_left()){
				/* - DASHED_LINE funktioniert nicht richtig bei einer Ellipse, darum SOLID_LINE - */
				setlinestyle(SOLID_LINE, 1);
				mouse_getpos(&xstart, &ystart);
				setwritemode(XOR_PUT);
				mouse_setcursor(crossCursor);

				/* - lese die momentanen Koordinaten ein und zeichne die Ellipse - */
				while(mouse_left()){
					mouse_getpos(&xmom, &ymom);
					/* da [xy]diff bei der Ellipse nur als Radius verwendet wird durch 2 dividieren */
					xdiff=(xmom-xstart)/2;
					ydiff=(ymom-ystart)/2;
					ellipse(xstart+xdiff, ystart+ydiff, 0, 360, xdiff, ydiff);
					xaend = xmom;
					yaend = ymom;

					/* nur eine neue Ellipse zeichnen, wenn die Maus bewegt wurde */
					while(xaend==xmom && yaend==ymom && mouse_left())
						mouse_getpos(&xaend, &yaend);
					ellipse(xstart+xdiff, ystart+ydiff, 0, 360, xdiff, ydiff);
				}
				/* wenn die linke Maustaste los gelassen wurde, dann durchgängige Ellipse zeichnen */
				setwritemode(COPY_PUT);
				setlinestyle(SOLID_LINE, 1);
				ellipse(xstart+xdiff, ystart+ydiff, 0, 360, xdiff, ydiff);
				erst_figur=0;
				erst_right=1;
				mouse_setcursor(arrowCursor);
			}

			/* -- wenn rechte Maustaste gedrückt, dann mit zufälliger Farbe füllen -- */
			if(mouse_right() && !erst_figur && erst_right){
				erst_right=0;
				setfillstyle(SOLID_FILL, rand()%getmaxcolor());
				fillellipse(xstart+xdiff, ystart+ydiff, xdiff, ydiff);
			}
		}

		/* wenn figur=4, dann zeichne Kreis */
		else if(figur == 4){
			/* -- zeichne Kreis, wenn die linke Maustaste gedrückt ist --- */
			if(mouse_left()){
				/* - DASHED_LINE funktioniert nicht richtig bei einem Kreis, darum SOLID_LINE - */
				setlinestyle(SOLID_LINE, 1);
				mouse_getpos(&xstart, &ystart);
				setwritemode(XOR_PUT);
				mouse_setcursor(crossCursor);

				/* - lese die momentanen Koordinaten ein und zeichne den Kreis - */
				while(mouse_left()){
					mouse_getpos(&xmom, &ymom);
					xdiff=xmom-xstart;
					ydiff=ymom-ystart;
					
					/* erst schauen, ob x größer y und abhängig davon den Radius festlegen */
					x_groesser = (abs(xdiff) >= abs(ydiff)) ? 1 : 0;
					if(xdiff < 0 && !(ydiff < 0))
						(x_groesser == 1) ? ymom=ystart-xdiff : xmom=xstart-ydiff;
					else if(ydiff < 0 && !(xdiff < 0))
						(x_groesser == 1) ? ymom=ystart-xdiff : xmom=xstart-ydiff;
					else
						(x_groesser == 1) ? ymom=ystart+xdiff : xmom=xstart+ydiff;

					/* [xy]diff für den Radius des Kreises neu berechnen - Division durch 2 */
					xdiff=(xmom-xstart)/2;
					ydiff=(ymom-ystart)/2;
					ellipse(xstart+xdiff, ystart+ydiff, 0, 360, xdiff, ydiff);
					xaend = xmom;
					yaend = ymom;

					/* nur einen neuen Kreis zeichnen, wenn die Maus bewegt wurde */
					while(xaend==xmom || yaend==ymom && mouse_left())
						mouse_getpos(&xaend, &yaend);
					ellipse(xstart+xdiff, ystart+ydiff, 0, 360, xdiff, ydiff);
				}
				/* wenn die linke Maustaste los gelassen wurde, dann durchgängigen Kreis zeichnen */
				/* dabei COPY_PUT verwenden, um den alten Kreis zu überschreiben */
				setwritemode(COPY_PUT);
				setlinestyle(SOLID_LINE, 1);
				ellipse(xstart+xdiff, ystart+ydiff, 0, 360, xdiff, ydiff);
				erst_figur=0;
				erst_right=1;
				mouse_setcursor(arrowCursor);
			}

			/* -- wenn rechte Maustaste gedrückt, dann mit zufälliger Farbe füllen -- */
			if(mouse_right() && !erst_figur && erst_right){
				erst_right=0;
				setfillstyle(SOLID_FILL, rand()%getmaxcolor());
				fillellipse(xstart+xdiff, ystart+ydiff, xdiff, ydiff);
			}
		}

		/* wenn figur=5, dann zeichne Linie */
		else if(figur == 5){
			/* -- zeichne gestrichelte Linie, wenn die linke Maustaste gedrückt ist --- */
			if(mouse_left()){
				setlinestyle(DASHED_LINE, 1);
				mouse_getpos(&xstart, &ystart);
				setwritemode(XOR_PUT);
				mouse_setcursor(crossCursor);

				/* - lese die momentanen Koordinaten ein und zeichne die Linie - */
				while(mouse_left()){
					mouse_getpos(&xmom, &ymom);
					line(xstart, ystart, xmom, ymom);
					xaend = xmom;
					yaend = ymom;

					/* nur eine neue Linie zeichnen, wenn die Maus bewegt wurde */
					while(xaend==xmom && yaend==ymom && mouse_left())
						mouse_getpos(&xaend, &yaend);
					line(xstart, ystart, xmom, ymom);
				}
				/* wenn die linke Maustaste los gelassen wurde, dann durchgängige Linie zeichnen */
				setwritemode(COPY_PUT);
				setlinestyle(SOLID_LINE, 1);
				line(xstart, ystart, xmom, ymom);
				erst_figur=0;
				erst_right=1;
				mouse_setcursor(arrowCursor);
			}
		}

		/* wenn figur=6, dann zeichne freie Form */
		else if(figur == 6){
			if(mouse_left()){
				/* - lese die Startkoordinaten der Form ein und setze Zeichen-Cursor darauf - */
				mouse_getpos(&xstart, &ystart);
				moveto(xstart, ystart);
				mouse_setcursor(crossCursor);

				/* - lese die momentanen Koordinaten ein und zeichne eine Zwischenlinie - */
				/* - nur putpixel() würde nicht ausreichen, der Rechner würde keine ganze Form zeichnen - */
				while(mouse_left()){
					mouse_getpos(&xmom, &ymom);
					lineto(xmom, ymom);
					xaend = xmom;
					yaend = ymom;

					/* nur eine neue Linie zeichnen, wenn die Maus bewegt wurde */
					while(xaend==xmom && yaend==ymom && mouse_left())
						mouse_getpos(&xaend, &yaend);
				}
				mouse_setcursor(arrowCursor);
			}
		}

		/* -- bei mittlerer Maustaste das Grafikfenster löschen -- */
		if(mouse_mid()){
			clearviewport(BLACK);
				erst_figur=1;
		}
	}

	/* --- Tastatur betätigt, also aufräumen und beenden --- */
	closegraph();
	return 0;
}

