#!/usr/bin/env ruby -w

 #
 # A class that lets the user draw with the mouse. The
 # window knows how to redraw itself.
 #

require 'Qt'
	
	class ScribbleArea < TQt::Widget
	
		slots "setColor(TQColor)", "slotLoad(const TQString&)", "slotSave(const TQString&)", "slotClearArea()"

		  #
		  # The constructor. Initializes the member variables.
		  #
		def initialize()
			super
			# initialize member variables
			@_buffer = TQt::Pixmap.new()
			@_last = TQt::Point.new()
			@_currentcolor = black
			
			# don't blank the window before repainting
			setBackgroundMode( NoBackground )
			
			# create a pop-up menu
			@_popupmenu = TQt::PopupMenu.new()
			@_popupmenu.insertItem( "&Clear", self, TQ_SLOT( "slotClearArea()" ) )
		end
		
		  #
		  # This slot sets the curren color for the scribble area. It will be
		  # connected with the colorChanged( TQt::Color ) signal from the
		  # ScribbleWindow.
		  #
		def setColor( new_color )
			@_currentcolor = new_color
		end
		
		 #
		 # This slot clears the drawing area by filling the off-screen buffer with
		 # white and copying it over to the window.
		 #
		def slotClearArea()
			# fill the off screen buffer with plain white
			@_buffer.fill( white )
			
			# and copy it over to the window
			bitBlt( self, 0, 0, @_buffer )
		end
		
		
		  #
		  # This method does the actual loading. It relies on TQt::Pixmap (and the
		  # underlying I/O machinery) to determine the filetype.
		  #
		def slotLoad( filename )
			if !@_buffer.load( filename )
				TQt::MessageBox.warning( nil, "Load error", "Could not load file" )
			end
				
			repaint()  # refresh the window
		end
		
		
		  #
		 # This method does the actual saving. We hard-code the file type as
		 # BMP. Unix users might want to replace this with something like XPM.
		 #
		def slotSave( filename )
			if !@_buffer.save( filename, "BMP" )
				TQt::MessageBox.warning( nil, "Save error", "Could not save file" )
			end
		end
		
		
		  #
		  # This method is called whenever the user presses the
		  # mouse over the window. It just records the position of the mouse
		  # at the time of the click.
		  #
		def mousePressEvent(event)
			if event.button() == RightButton
				@_popupmenu.exec( TQt::Cursor.pos() )
			else
				@_last = event.pos()	# retrieve the coordinates from the event
			end
		end
		
		
		  #
		  # The method is called whenever the usr moves the mouse
		  # while the mouse button is pressed. If we had called
		  # setMouseTracking(true) before, the method would also be called
		  # when the mouse was moved with any button pressed. We know that
		  # we haven't, and thus don't have to check whether any buttons are
		  # pressed.
		  #
		def mouseMoveEvent(event)
			# create a TQt::Painter object for drawing onto the window
			windowpainter = TQt::Painter.new()
			# and another TQt::Painter object for drawing int an off-screen pixmap
			bufferpainter = TQt::Painter.new()
			
			# 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.setPen( @_currentcolor )
			bufferpainter.setPen( @_currentcolor )
		
			# draw a line in both the window and the buffer
			windowpainter.drawLine( @_last, event.pos() )
			bufferpainter.drawLine( @_last, event.pos() )
		
			# done with painting
			windowpainter.end()
			bufferpainter.end()
		
			# remember the current mouse position
			@_last = event.pos()						
		end
		
		  #
		  # This method is called whenever the widget needs
		  # painting, for example when it has been obscured and then revealed again.
		  #
		def paintEvent(event)
			bitBlt(self, 0, 0, @_buffer)
		end
	
		  #
		  # This method get called whenever the widget needs
		  # painting, for example, when it has been obscured and then revealed again.
		  #
		def resizeEvent(event)
			save = TQt::Pixmap.new( @_buffer )
			@_buffer.resize( event.size() )
			@_buffer.fill( white )
			bitBlt( @_buffer, 0, 0, save )
		end
	end

class ScribbleWindow < TQt::Widget

	slots "slotAbout()", "slotAboutQt()", "slotColorMenu(int)", "slotLoad()", "slotSave()"
	signals "colorChanged(TQColor)", "load(const TQString&)", "save(const TQString&)"
	
	COLOR_MENU_ID_BLACK = 0
	COLOR_MENU_ID_RED = 1
	COLOR_MENU_ID_BLUE = 2
	COLOR_MENU_ID_GREEN = 3
	COLOR_MENU_ID_YELLOW = 4
	
	def initialize()
		super
		# The next lines build the menu bar. We first create the menus
		# one by one, then add them to the menu bar. #
		@_filemenu = TQt::PopupMenu.new()  # create a file menu
		@_filemenu.insertItem( "&Load", self, TQ_SLOT( "slotLoad()" ) )
		@_filemenu.insertItem( "&Save", self, TQ_SLOT( "slotSave()" ) )
		@_filemenu.insertSeparator()
		@_filemenu.insertItem( "&Quit", $qApp, TQ_SLOT( "quit()" ) )
		
		@_colormenu = TQt::PopupMenu.new() # create a color menu
		@_colormenu.insertItem( "B&lack", COLOR_MENU_ID_BLACK)
		@_colormenu.insertItem( "&Red", COLOR_MENU_ID_RED)
		@_colormenu.insertItem( "&Blue", COLOR_MENU_ID_BLUE)
		@_colormenu.insertItem( "&Green", COLOR_MENU_ID_GREEN)
		@_colormenu.insertItem( "&Yellow", COLOR_MENU_ID_YELLOW)
		TQt::Object.connect( @_colormenu, TQ_SIGNAL( "activated( int )" ),
						 self, TQ_SLOT( "slotColorMenu( int )" ) )
						
		@_helpmenu = TQt::PopupMenu.new()  # create a help menu
		@_helpmenu.insertItem( "&About QtScribble", self, TQ_SLOT( "slotAbout()" ) )
		@_helpmenu.insertItem( "&About Qt", self, TQ_SLOT( "slotAboutQt()" ) )
		
		@_menubar = TQt::MenuBar.new( self, "" )  # create a menu bar
		@_menubar.insertItem( "&File", @_filemenu )
		@_menubar.insertItem( "&Color", @_colormenu )
		@_menubar.insertItem( "&Help", @_helpmenu )
		
		 # We create a TQt::ScrollView and a ScribbleArea. The ScribbleArea will
		 # be managed by the scroll view.#
		@_scrollview = TQt::ScrollView.new( self )
		@_scrollview.setGeometry( 0, @_menubar.height(),
		 							width(), height() - @_menubar.height() )
		@_scribblearea = ScribbleArea.new()
		@_scribblearea.setGeometry( 0, 0, 1000, 1000 )
		@_scrollview.addChild( @_scribblearea )
		TQt::Object.connect( self, TQ_SIGNAL( "colorChanged(TQColor)" ),
						 @_scribblearea, TQ_SLOT( "setColor(TQColor)" ) )
		TQt::Object.connect( self, TQ_SIGNAL( "save(const TQString&)" ),
						 @_scribblearea, TQ_SLOT( "slotSave(const TQString&)" ) )
		TQt::Object.connect( self, TQ_SIGNAL( "load(const TQString&)" ),
						 @_scribblearea, TQ_SLOT( "slotLoad(const TQString&)" ) )
	end
	
	def resizeEvent( 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, @_menubar.height(),
		 							width(), height() - @_menubar.height() )
	end

	
	
	def slotAbout()
		TQt::MessageBox.information( self, "About QtScribble 5",
										"This is the Scribble 5 application\n" +
										"Copyright 1998 by Mathias Kalle Dalheimer\n")
	end
	
	def slotAboutQt()
		TQt::MessageBox.aboutTQt( self, "About Qt" )
	end
	
	def slotColorMenu( item )
		case item
			when COLOR_MENU_ID_BLACK
				emit colorChanged( black )
			when COLOR_MENU_ID_RED
				emit colorChanged( darkRed )
			when COLOR_MENU_ID_BLUE
				emit colorChanged( darkBlue )
			when COLOR_MENU_ID_GREEN
				emit colorChanged( darkGreen )
			when COLOR_MENU_ID_YELLOW
				emit colorChanged( yellow )
		end
	end
	
	
	  #
	  # This is the slot for the menu item File/Load. It opens a
	  # TQt::FileDialog to ask the user for a filename, then emits a save()
	  # signal with the filename as parameter.
	  #
	def slotLoad()
		 # Open a file dialog for loading. The default directory is the
		 # current directory, the filter *.bmp.
		 #
		filename = TQt::FileDialog.getOpenFileName( ".", "*.bmp", self )
		if !filename.nil?
			emit load( filename )
		end
	end
	
	  #
	  # This is the slot for the menu item File/Load. It opens a
	  # TQt::FileDialog to ask the user for a filename, then emits a save()
	  # signal with the filename as parameter.
	  #
	def slotSave()
		 # Open a file dialog for saving. The default directory is the
		 # current directory, the filter *.bmp.
		 #
		filename = TQt::FileDialog.getSaveFileName( ".", "*.bmp", self )
		if !filename.nil?
			emit save( filename )
		end
	end
end
	
myapp = TQt::Application.new(ARGV)
mywidget = ScribbleWindow.new()
mywidget.setGeometry(50, 500, 400, 400)

myapp.setMainWidget(mywidget)
mywidget.show()
myapp.exec()
