=begin
/****************************************************************************
** $Id: qt/examples/xform/xform.cpp   2.3.0   edited 2001-01-26 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/
=end
#include <qapplication.h>

#include <qdialog.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <qcheckbox.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qlcdnumber.h>
#include <qslider.h>
#include <qmenubar.h>
#include <qfontdialog.h>
#include <qlayout.h>
#include <qvbox.h>
#include <qwidgetstack.h>

#include <qpainter.h>
#include <qpixmap.h>
#include <qpicture.h>

#include <stdlib.h>
require "qt2"
include Qt2


Text=0
Image=1
Picture=2
class ModeNames
#    attr_accessor mode,  mext, image, picture
end


class XFormControl < QVBox
attr_reader :snewMatrix, :snewText, :snewFont, :snewMode
 def initialize( parent=nil,name="" )
      @snewMatrix = RSignal.new("Object")
      @snewText = RSignal.new("Object")
      @snewFont = RSignal.new("Object")
      @snewMode = RSignal.new("Object")
 #private:
    @mode
    @rotS		       #// Rotation angle scroll bar
    @shearS	       #// Shear value scroll bar
    @magS		       #// Magnification value scroll bar
    @rotLCD	       #// Rotation angle LCD display
    @shearLCD	       #// Shear value LCD display
    @magLCD	       #// Magnification value LCD display
    @mirror	       #// Checkbox for mirror image on/of
    @optionals
    @textEd	       #// Inp[ut field for xForm text
    @fpb		       #// Select font push button
    @rb_txt	       #// Radio button for text
    @rb_img	       #// Radio button for image
    @rb_pic	       #// Radio button for picture
    @currentFont
    super( parent, name )
    setSpacing(6)
    setMargin(6)
    #@currentFont = initialFont
    @mode = Image

    @rotLCD	= QLCDNumber.new( 4, self, "rotateLCD" )
    @rotS	= QSlider.new( QSlider::Horizontal, self,
				  "rotateSlider" )
    @shearLCD	= QLCDNumber.new( 5,self, "shearLCD" )
    @shearS	= QSlider.new( QSlider::Horizontal, self,"shearSlider" )
    @mirror	= QCheckBox.new( self, "mirrorCheckBox" )
    @rb_txt = QRadioButton.new( self, "text" )
    @rb_img = QRadioButton.new( self, "image" )
    @rb_pic = QRadioButton.new( self, "picture" )
    @optionals = QWidgetStack.new(self)
    optionals_text = QVBox.new(@optionals)
    optionals_text.setSpacing(6)
    optionals_other = QVBox.new(@optionals)
    optionals_other.setSpacing(6)
    @optionals.addWidget(optionals_text,0)
    @optionals.addWidget(optionals_other,1)
    @fpb		= QPushButton.new( optionals_text, "text" )
    @textEd	= QLineEdit.new( optionals_text, "text" )
    @textEd.setFocus()

    @rotLCD.display( "  0'" )

    @rotS.setRange( -180, 180 )
    @rotS.setValue( 0 )
    Qt2::connect( @rotS, QSIGNAL("valueChanged(int)"), self , "newMtx()" )

    @shearLCD.display( "0.00" )

    @shearS.setRange( -25, 25 )
    @shearS.setValue( 0 )
    Qt2::connect( @shearS, QSIGNAL("valueChanged(int)"), self, "newMtx()" )

    @mirror.setText( tr("Mirror") )
    Qt2::connect( @mirror, QSIGNAL("clicked()"), self ,"newMtx()" )

    @bg = QButtonGroup.new(self)
    @bg.hide()
    @bg.insert(@rb_txt,0)
    @bg.insert(@rb_img,1)
    @bg.insert(@rb_pic,2)
    @rb_txt.setText( tr("Text") )
    @rb_img.setText( tr("Image") )
    @rb_img.setChecked(true)
    @rb_pic.setText( tr("Picture") )
    Qt2::connect( @bg, QSIGNAL("clicked(int)"), self, "changeMode(int)" )

    @fpb.setText( tr("Select font...") )
    Qt2::connect( @fpb, QSIGNAL("clicked()"), self, "selectFont()" )

    @textEd.setText( "Troll" )
    Qt2::connect( @textEd, QSIGNAL("textChanged(const QString&)"),
		     self, "newTxt(const QString&)")

    @magLCD = QLCDNumber.new( 4,optionals_other, "magLCD" )
    @magLCD.display( "100" )
    @magS = QSlider.new( QSlider::Horizontal, optionals_other,
			   "magnifySlider" )
    @magS.setRange( 0, 800 )
    Qt2::connect( @magS, QSIGNAL("valueChanged(int)"), self, "newMtx()" )
    @magS.setValue( 0 )
    Qt2::connect( @magS, QSIGNAL("valueChanged(int)"), @magLCD, QSLOT("display(int)"))

    optionals_text.adjustSize()
    optionals_other.adjustSize()
    changeMode(Image)

    startTimer(20) # start an initial animation
    catchEvent
end

def setFont(f)
   @currentFont = f
end

def timerEvent( e )

    v = @magS.value()
    v = (v+2)+v/10
    if ( v >= 200 )
	v = 200
	killTimers()
    end
    @magS.setValue(v)
end


=begin
/*
    Called whenever the user has changed one of the matrix parameters
    (i.e. rotate, shear or magnification)
*/
=end
def newMtx(dummy=0)
    @snewMatrix.sendWith( matrix() )
end

def newTxt( s)
    @snewText.sendWith(s)
    changeMode(Text)
end
=begin
/*
    Calculates the matrix appropriate for the current controls,
    and updates the displays.
*/
=end
def matrix()
    m = QWMatrix.new
    if (@mode != Text)
	magVal = 1.0*@magS.value()/100
	m.scale( magVal, magVal )
    end
    shearVal = 1.0*@shearS.value()/25
    m.shear( shearVal, shearVal )
    m.rotate( @rotS.value() )
    if ( @mirror.isChecked() )
	m.scale( 1, -1 )
	m.rotate( 180 )
    end

    tmp="#{shearVal}"
    if ( shearVal >= 0 )
	tmp = " " + tmp
    end
    @shearLCD.display( tmp )

    rot = @rotS.value()
    if ( rot < 0 )
	rot = rot + 360
    end
    tmp = "#{rot}"
    @rotLCD.display( tmp )
    return m
end


def selectFont()

    ok = true
    f = QFontDialog::getFont( ok, @currentFont )
    if ( f[1] )
            f[0].setCharSet(QFont::charSetForLocale())
	@currentFont = f[0]
	fontSelected( f[0] )
    end
end

def fontSelected( font )

    @snewFont.sendWith( font )
    changeMode(Text)
end
=begin
/*
    Sets the mode - Text, Image, or Picture.
*/
=end
def changeMode( m)

    @mode = m

    @snewMode.sendWith( m )
    newMtx()
    if ( @mode == Text )
	@optionals.raiseWidget(0)
	@rb_txt.setChecked(true)
    else
	@optionals.raiseWidget(1)
	if ( @mode == Image )
	    @rb_img.setChecked(true)
	else
	    @rb_pic.setChecked(true)
             end
    end
    QApplication::flushX()
end
end

=begin
/*
  ShowXForm displays a text or a pixmap (QPixmap) using a coordinate
  transformation matrix (QWMatrix)
*/
=end
class ShowXForm < QWidget


def initialize(parent =nil, name="")
   super( parent, name, WResizeNoErase )

    #setFont( initialFont )
    setBackgroundColor( Qt::white )
    @m = Text
    @eraseRect = QRect.new( 0, 0, 0, 0 )
    @mtx = QWMatrix.new			# coordinate transform matrix
    @text = nil			# text to be displayed
    @pix =nil			# pixmap to be displayed
    @picture =QPixmap.new(nil)			# text to be displayed
    @eraseRect = QRect.new( 0, 0, 0, 0 )	# covers last displayed text/pixmap
    @m = nil
    catchEvent
end

def sizePolicy()

    return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding )
end

def sizeHint()

    return QSize(400,400)
end

def paintEvent( e )

    showIt()
end

def resizeEvent( e )

    @eraseRect = QRect.new( width()/2, height()/2, 0, 0 )
    repaint(rect())
end

def mode()
   @m
end
   
def setText(  s )
    @text = s
    showIt()
end

def setMatrix( w )

    @mtx = w
    showIt()
end

def setFont( f )
    @m = Text
    super( f )
end

def setPixmap( pm )

    @pix	 = pm
    @m    = Image
    showIt()
end

def setPicture(  p )

    @picture = p
    @m = Picture
    showIt()
end

def setMode(  mode )

    @m = mode
end

def showIt()

    p = QPainter.new
    #QRect r	  # rectangle covering new text/pixmap in virtual coordinates
    um = QWMatrix.new  # copy user specified transform
    textYPos = 0 # distance from boundingRect y pos to baseline
    textXPos = 0 # distance from boundingRect x pos to text start
    #QRect br
    fm = fontMetrics()	# get widget font metrics
    case ( mode() )
      when Text
	br = fm.boundingRect( QString::fromLocal8Bit(@text) )	# rectangle covering text
        r  = br
	#r.setHeight(r.height() + 10)
	textYPos = -r.y() # + 10
	textXPos = -r.x()
	br.moveTopLeft( QPoint.new( -br.width()/2, -br.height()/2 ) )
      when Image
	r = @pix.rect()
      when Picture
	# ### need QPicture::boundingRect()
	r = QRect.new(0,0,1000,1000)
    end
    r.moveTopLeft( QPoint.new(-r.width()/2, -r.height()/2) )
	  # compute union of new and old rect
	  # the resulting rectangle will cover what is already displayed
	  # and have room for the new text/pixmap
    @eraseRect = @eraseRect.unite( @mtx.map(r) )
    @eraseRect.moveBy( -1, -1 ) # add border for matrix round off
    @eraseRect.setSize( QSize.new( @eraseRect.width() + 2, @eraseRect.height() + 2 ) )
    pw = QMIN(@eraseRect.width(),width()) 
    ph = QMIN(@eraseRect.height(),height()) 
    pm = QPixmap.new( QSize.new(pw, ph) )		# off-screen drawing pixmap
    pm.fill( backgroundColor() )

    p.begin( pm )
    um.translate( pw/2, ph/2 )	# 0,0 is center
    um = @mtx.mul(um)
    p.setWorldMatrix( um )
    case ( mode() )
      when Text
	p.setFont( font() )		# use widget font
    if(@text.size > 0)
	  p.drawText( r.left() + textXPos, r.top() + textYPos, QString::fromLocal8Bit(@text) )
#if 0
	#p.setPen( QColor("red") )
	#p.drawRect( br )
#endif
    end
      when Image
	p.drawPixmap( -@pix.width()/2, -@pix.height()/2, @pix )
	#QPixmap rotated = pix.xForm(mtx)
	#bitBlt( &pm, pm.width()/2 - rotated.width()/2,
		#pm.height()/2 - rotated.height()/2, &rotated )
      when Picture
	# ### need QPicture::boundingRect()
	p.scale(0.25,0.25)
	p.translate(-230,-180)
	p.drawPicture( @picture )
    end
    p.end()

    xpos = width()/2  - pw/2
    ypos = height()/2 - ph/2
    bitBlt( self, xpos, ypos,			# copy pixmap to widget
	    pm, 0, 0, -1, -1 )
    @eraseRect =	 @mtx.map( r )
end
end

=begin
/*
    Grand unifying widget, putting ShowXForm and XFormControl
    together.
*/
=end
class XFormCenter < QHBox
def initialize( parent=nil, name="" )
    super( parent, name )

    f = QFont.new( "Charter", 36, QFont::Bold )
    f.setCharSet(QFont::charSetForLocale())

    @xc = XFormControl.new( self )
    @xc.setFont(f)
    @sx = ShowXForm.new(  self )
    @sx.setFont(f)
    setStretchFactor(@sx,1)
    @xc.setFrameStyle( QFrame::Panel | QFrame::Raised )
    @xc.setLineWidth( 2 )
    Qt2::connect( @xc.snewText, @sx,
		 "setText" )
    Qt2::connect( @xc.snewMatrix,
	     @sx, "setMatrix" )
    Qt2::connect( @xc.snewFont, @sx,
		 "setFont")
    Qt2::connect( @xc.snewMode, self , "newMode" )
    @sx.setText( "Troll" )
    newMode( Image )
    @sx.setMatrix(@xc.matrix())
end

def newMode( m )

    @first_i = true
    @first_p = true

    if ( @sx.mode() == m )
	return
   end
    if ( (m == Image) && @first_i )
	@first_i = false
	pm = QPixmap.new()
	if ( pm.load( "image.any" ) )
	    @sx.setPixmap( pm )
             end
	return
    end
    if ( (m == Picture) && @first_p )
	@first_p = false
	p = QPicture.new
	if (p.load( "picture.any" ))
	    @sx.setPicture( p )
             end
	return

    end
    @sx.setMode(m)
end


end


    a = QApplication.new([$0]+ARGV)

    xfc = XFormCenter.new
    xfc.resize(600,400)
    a.setMainWidget( xfc )
    xfc.show()
    a.exec()

