/***************************************************************************
                          main.m  -  description
                             -------------------
    begin                : Fri Mar 17 15:04:11 EST 2000
    copyright            : (C) 2000 by Richard Dale
    email                : Richard_Dale@tipitina.demon.co.uk
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <Foundation/NSString.h>

#include <qtobjc/Qt.h>
#include <qtobjc/QObject.h>
#include <qtobjc/QApplication.h>
#include <qtobjc/QFileDialog.h>
#include <qtobjc/QMenuBar.h>
#include <qtobjc/QMessageBox.h>
#include <qtobjc/QPainter.h>
#include <qtobjc/QPaintDevice.h>
#include <qtobjc/QPixmap.h>
#include <qtobjc/QPopupMenu.h>
#include <qtobjc/QScrollView.h>
#include <qtobjc/QWidget.h>

/**
 * 'Programming with Qt' Example 3-4 page 64
 */

 enum MenuIDs {
 	COLOR_MENU_ID_BLACK,
 	COLOR_MENU_ID_RED,
 	COLOR_MENU_ID_BLUE,
 	COLOR_MENU_ID_GREEN,
 	COLOR_MENU_ID_YELLOW };
 	

/**
 * A class that lets the user draw scribbles with the mouse. The
 * window knows how to redraw itself.
 */
@interface ScribbleArea : QWidget
{
@private
	QPoint *		_last;
	QColor *		_currentcolor;
	
	QPixmap *	_buffer;
	QPopupMenu *	_popupmenu;
}

- init;
- (void) dealloc;

- (void) setColor: (QColor *) color;
- (void) slotLoad: (NSString *) name;
- (void) slotSave: (NSString *) name;

- (void) mousePressEvent: (QMouseEvent *) event;
- (void) mouseMoveEvent: (QMouseEvent *) event;
- (void) paintEvent: (QPaintEvent *) event;
- (void) resizeEvent: (QResizeEvent *) event;

- (void) slotClearArea;
@end

@interface ScribbleWindow : QWidget
{
@private
	QMenuBar *	_menubar;
	QPopupMenu *	_filemenu;
	QPopupMenu *	_colormenu;
	QPopupMenu *	_helpmenu;
	QScrollView *	_scrollview;
	ScribbleArea *	_scribblearea;
}

- init;
- (void) dealloc;

- (void) slotAbout;
- (void) slotAboutQt;
- (void) slotColorMenu: (int) item;
- (void) slotLoad;
- (void) slotSave;

- (void) resizeEvent: (QResizeEvent *) event;

@end

@implementation ScribbleArea

- init
{
	[super init];
	// initialize instance variables
	_buffer = [[QPixmap alloc] init];
	_currentcolor = [Qt black];
	
	// don't blank the window before repainting
	[self setBackgroundMode: [QWidget NoBackground]];
	
	// create a pop-up menu
	_popupmenu = [[QPopupMenu alloc] init];
	[_popupmenu insertTextItem: @"&Clear" receiver: self slot: @"slotClearArea"];
	return self;
}

- (void) dealloc
{
	[_popupmenu release];
	[super dealloc];
	return;
}


/**
  * This slot sets the current color for the scribble area. It will be
  * connected with the colorChanged: signal from the
  * ScribbleWindow
  */
- (void) setColor: (QColor *) new_color
{
	_currentcolor = new_color;
}

/**
  * This slot clears the drawing area by filling the otff-screen buffer with
  * white and coping it over to the window
  */
- (void) slotClearArea
{
	[_buffer fill: [Qt white]];
	[QPaintDevice bitBlt: self dx: 0 dy: 0 source: _buffer];
}

- (void) slotLoad: (NSString *) filename
{
	if (![_buffer load: filename])
		[QMessageBox warning: nil caption: @"Load error" text: @"Could not load file"];
	
	[self repaint];
}

- (void) slotSave: (NSString *) filename
{
	if (![_buffer save: filename format: @"BMP"])
		[QMessageBox warning: nil caption: @"Save error" text: @"Could not save file"];
}

	
/**
  * The method is called whenever the user presses the
  * mouse over the window. When the right mouse button is pressed, it
  * pops up a previously constructed pop-up menu. Otherwise, it just
  * records the position of the mouse at the time of the click.
  */
- (void) mousePressEvent: (QMouseEvent *) event
{
	if ([event button] == [Qt RightButton]) {
		[_popupmenu exec: [QCursor pos]];
	} else {
		_last = [[event pos] retain];
	}
}


/**
  * This method is called whenever the user moves the mouse
  * while the mouse button is pressed. If we had called
  * - setMouseTracking: YES before, the method would also be called
  * when the mouse has moved without any button pressed. We know that
  * we haven't, and thus don't have to check whether any buttons are
  * pressed.
  */
- (void) mouseMoveEvent: (QMouseEvent *) event
{
	// create a QPainter object for drawing onto the window
	QPainter *	windowpainter = [[[QPainter alloc] init] autorelease];
	// create a QPainter object for drawing into an off-screen pixmap
	QPainter *	bufferpainter = [[[QPainter alloc] init] autorelease];
	
	// start painting
	[windowpainter begin: self]; 			// this painter paints onto the window
	[bufferpainter begin: _buffer];		// and this one paints in the buffer
	
	// set a standard pen with the currently selected color
	[windowpainter setPenColor: _currentcolor];
	[bufferpainter setPenColor: _currentcolor];
	
	// draw a line in both the window and the buffer
	[windowpainter drawLine: _last point: [event pos]];
	[bufferpainter drawLine: _last point: [event pos]];
	
	// done with painting
	[windowpainter end];
	[bufferpainter end];
	
	// remember the current mouse position
	_last = [[event pos] retain];
}


/**
  * This method is called whenever the widget needs
  * painting, for example, when it has been obscured and then revealed again.
  */
- (void) paintEvent: (QPaintEvent *) event
{
	[QPaintDevice bitBlt: self dx: 0 dy: 0 source: _buffer];
}


/**
  * This method gets called whenever the window is resized. We
  * use it to make sure that the off-screen buffer is always the same
  * size as the window.
  * In order to retain the original scribbling, it is first copied
  * to a temporary buffer. After the main buffer has been resized and
  * filled with white, the image is copied from the temporary buffer to
  * the main buffer
  */
- (void) resizeEvent: (QResizeEvent *) event
{
	QPixmap * save = [[_buffer copy] autorelease];
	[_buffer resize: [event size]];
	[_buffer fill: [Qt white]];
	[QPaintDevice bitBlt: _buffer dx: 0 dy: 0 source: save];
}

@end

@implementation ScribbleWindow

/** The initializer. Initializes the instance variables and the menu
  * system
  */
- init
{
	[super init];
	
	/* The next lines build the menu bar. We first create the menus
	 * one by one, then add them to the menu bar. */
	_filemenu = [[QPopupMenu alloc] init];					// create a file menu
	[_filemenu insertTextItem: @"&Load" receiver: self slot: @"slotLoad"];
	[_filemenu insertTextItem: @"&Save" receiver: self slot: @"slotSave"];
	[_filemenu insertSeparator];
	[_filemenu insertTextItem: @"&Quit" receiver: [QApplication qApp] slot: @"quit()"];
	
	_colormenu = [[QPopupMenu alloc] init];  				// create a color menu
	[_colormenu insertTextItem: @"B&lack" identifier: COLOR_MENU_ID_BLACK];
	[_colormenu insertTextItem: @"&Red" identifier: COLOR_MENU_ID_RED];
	[_colormenu insertTextItem: @"&Blue" identifier: COLOR_MENU_ID_BLUE];
	[_colormenu insertTextItem: @"&Green" identifier: COLOR_MENU_ID_GREEN];
	[_colormenu insertTextItem: @"&Yellow" identifier: COLOR_MENU_ID_YELLOW];
	[	QObject	connect: _colormenu signal: @"activated(int)"
				receiver: self slot: @"slotColorMenu:" ];
	
	_helpmenu = [[QPopupMenu alloc] init];					// create a help menu
	[_helpmenu insertTextItem: @"&About QtScribble" receiver: self slot: @"slotAbout"];
	[_helpmenu insertTextItem: @"About &Qt" receiver: self slot: @"slotAboutQt"];
	
	_menubar = [[QMenuBar alloc] initWithWidget: self];		// create a menu bar
	[_menubar insertTextItem: @"&File" popup: _filemenu];
	[_menubar insertTextItem: @"&Color" popup: _colormenu];
	[_menubar insertSeparator];
	[_menubar insertTextItem: @"&Help" popup: _helpmenu];
	
	_scrollview = [[QScrollView alloc] initWithWidget: self];
	[_scrollview setGeometry: 0 y: [_menubar height] w: [self width] h: [self height] - [_menubar height]];
	_scribblearea = [[ScribbleArea alloc] init];
	[_scribblearea setGeometry: 0 y: 0 w: 1000 h: 1000];
	[_scrollview addChild: _scribblearea];
	[	QObject 	connect: self signal: @"colorChanged:"
				receiver: _scribblearea slot: @"setColor:" ];
	[	QObject	connect: self signal: @"save:"
				receiver: _scribblearea slot: @"slotSave:" ];
	[	QObject	connect: self signal: @"load:"
				receiver: _scribblearea slot: @"slotLoad:"] ;
	
	return self;
}

/**
  * The memory deallocation method. Does nothing for now.
  */
- (void) dealloc
{
	[super dealloc];
	return;
}



/**
  * This method gets called whenever the window is resized. We
  */
- (void) resizeEvent: (QResizeEvent *) event
{
	/* When the whole window is resized, we have to rearrange the geometry
	 * in the ScribbleWindow as well. Note that the ScribbleArea does not need
	 * to be changed. */
	[_scrollview setGeometry: 0 y: [_menubar height] w: [self width] h: [self height] - [_menubar height]];
}


- (void) slotAbout
{
	[	QMessageBox information: self caption: @"About QtScribble 3"
			text:	@"This is the QtScribble 2 application\n"
					@"Copyright 1998 by Matthias Kalle Dalheimer\n" ];
}

- (void) slotAboutQt
{
	[QMessageBox aboutQt: self caption: @"About Qt"];
}

- (void) slotColorMenu: (int) item
{
	switch (item) {
	case COLOR_MENU_ID_BLACK:
		[self emit: @"colorChanged:" value: [Qt black]];
		break;
	case COLOR_MENU_ID_RED:
		[self emit: @"colorChanged:" value: [Qt red]];
		break;
	case COLOR_MENU_ID_BLUE:
		[self emit: @"colorChanged:" value: [Qt blue]];
		break;
	case COLOR_MENU_ID_GREEN:
		[self emit: @"colorChanged:" value: [Qt green]];
		break;
	case COLOR_MENU_ID_YELLOW:
		[self emit: @"colorChanged:" value: [Qt yellow]];
		break;
	}
}


- (void) slotLoad
{
	NSString * filename = [QFileDialog getOpenFileName: @"." filter: @"*.bmp" parent: self name: @""];
	if ([filename length] > 0)
		[self emit: @"load:" value: filename];
}


- (void) slotSave
{
	NSString * filename = [QFileDialog getSaveFileName: @"." filter: @"*.bmp" parent: self name: @""];
	
	if ([filename length] > 0)
		[self emit: @"save:" value: filename];
}
	
@end

int main(int argc, char *argv[])
{
	QApplication * myapp = [[QApplication alloc] initWithArgc: argc argv: argv];
	
	QWidget * mywidget = [[ScribbleWindow alloc] init];
	[mywidget setGeometry: 50 y: 500 w: 400 h: 400];
	
	[myapp setMainWidget: mywidget];
	[mywidget show];
	
	return [myapp exec];
}
