/*************************************************************************** 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 #endif #include #include #include #include #include #include #include #include #include #include /** * '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]; }