/*************************************************************************
 *
 *  $RCSfile: svdsnpv.hxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: hr $ $Date: 2000/09/18 17:01:01 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SVDSNPV_HXX
#define _SVDSNPV_HXX

#include <svx/svdpntv.hxx>

#ifndef _SVDHLPLN_HXX
#include <svx/svdhlpln.hxx>
#endif

//************************************************************
//   Defines
//************************************************************

#define SDRSNAP_NOTSNAPPED  0x0000
#define SDRSNAP_XSNAPPED    0x0001
#define SDRSNAP_YSNAPPED    0x0002
#define SDRSNAP_XYSNAPPED   0x0003

// SDRCROOK_STRETCH ist noch nicht implementiert!
enum SdrCrookMode {
	SDRCROOK_ROTATE,
	SDRCROOK_SLANT,
	SDRCROOK_STRETCH
};

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  @@@@  @@  @@  @@@@  @@@@@   @@ @@ @@ @@@@@ @@   @@
// @@  @@ @@@ @@ @@  @@ @@  @@  @@ @@ @@ @@    @@   @@
// @@     @@@@@@ @@  @@ @@  @@  @@ @@ @@ @@    @@ @ @@
//  @@@@  @@@@@@ @@@@@@ @@@@@   @@@@@ @@ @@@@  @@@@@@@
//     @@ @@ @@@ @@  @@ @@       @@@  @@ @@    @@@@@@@
// @@  @@ @@  @@ @@  @@ @@       @@@  @@ @@    @@@ @@@
//  @@@@  @@  @@ @@  @@ @@        @   @@ @@@@@ @@   @@
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

class SdrSnapView: public SdrPaintView
{
protected:
	SdrPageView*				pDragHelpLinePV;  // Bei verschieben: PageView, sonst NULL

	Size						aMagnSiz;
	Size						aSnapSiz; // muss dann mal raus
#ifndef TF_FRACTIONGRID
	Fraction					aSnapWdtX;
	Fraction					aSnapWdtY;
#endif
	SdrHelpLine					aDragHelpLine;    // Die neue oder Kopie der zu verschiebenden Hilfslinie
	Point						aLastMausPosNoSnap;

	USHORT						nMagnSizPix;
	USHORT						nDragHelpLineNum; // Bei verschieben: Index, sonst undefiniert
	long						nSnapAngle;
	long						nEliminatePolyPointLimitAngle;

	SdrCrookMode				eCrookMode;

	unsigned					bSnapEnab : 1;
	unsigned					bGridSnap : 1;
	unsigned					bSnapTo1Pix : 1;             // Wenn GridSnap aus, auf ein Pixel fangen um Werte wie 10.01 zu vermeiden
	unsigned					bBordSnap : 1;
	unsigned					bHlplSnap : 1;
	unsigned					bOFrmSnap : 1;
	unsigned					bOPntSnap : 1;
	unsigned					bOConSnap : 1;
	unsigned					bMoveMFrmSnap : 1;
	unsigned					bMoveOFrmSnap : 1;
	unsigned					bMoveOPntSnap : 1;
	unsigned					bMoveOConSnap : 1;
	unsigned					bMoveSnapOnlyTopLeft : 1;    //  Speacial fuer den Dialogeditor
	unsigned					bOrtho : 1;
	unsigned					bBigOrtho : 1;
	unsigned					bAngleSnapEnab : 1;
	unsigned					bMoveOnlyDragging : 1;       // Objekte nur verschieben bei Resize/Rotate/...
	unsigned					bSlantButShear : 1;          // Slant anstelle von Shear anwenden
	unsigned					bCrookNoContortion : 1;      // Objekte bei Crook nicht verzerren
	unsigned					bSetPageOrg : 1;             // Interaktives setzen des Seitenursprungs
	unsigned					bDragHelpLine : 1;    // TRUE wenn Drag vorhandene oder neue Hilfslinie
	unsigned					bHlplFixed : 1;       // TRUE=Hilfslinien fixiert, also nicht verschiebbar
	unsigned					bEliminatePolyPoints : 1;

private:
	void ClearVars();

protected:
	// Alles togglen was als Xor im Win, nix merken! NULL=alle OutDev
	void ShowSetPageOrg(OutputDevice* pOut);
	void HideSetPageOrg(OutputDevice* pOut);
	void DrawSetPageOrg(OutputDevice* pOut) const;
	void ShowDragHelpLine(OutputDevice* pOut);
	void HideDragHelpLine(OutputDevice* pOut);
	void DrawDragHelpLine(OutputDevice* pOut) const;
	virtual void WriteRecords(SvStream& rOut) const;
	virtual BOOL ReadRecord(const SdrIOHeader& rViewHead, const SdrNamedSubRecord& rSubHead,SvStream& rIn);
public:
	SdrSnapView(SdrModel* pModel1, OutputDevice* pOut=NULL);
	SdrSnapView(SdrModel* pModel1, ExtOutputDevice* pXOut);

	virtual void ToggleShownXor(OutputDevice* pOut, const Region* pRegion) const;
	virtual BOOL IsAction() const;
	virtual void MovAction(const Point& rPnt);
	virtual void EndAction();
	virtual void BckAction();
	virtual void BrkAction(); // f.abg.Klassen Actions z,B, Draggen abbrechen.
	virtual void TakeActionRect(Rectangle& rRect) const;

	// Alle Fangeinstellungen sind Persistent.
	/*alt*/void SetSnapGrid(const Size& rSiz) { aSnapSiz=rSiz; SetSnapGridWidth(Fraction(rSiz.Width(),1),Fraction(rSiz.Height(),1)); }
	/*alt*/const Size& GetSnapGrid() const { return aSnapSiz; }

	void SetSnapGridWidth(const Fraction& rX, const Fraction& rY) { aSnapWdtX=rX; aSnapWdtY=rY; SnapMove(); }
	const Fraction& GetSnapGridWidthX() const { return aSnapWdtX; }
	const Fraction& GetSnapGridWidthY() const { return aSnapWdtY; }

	void SetSnapMagnetic(const Size& rSiz) { if (rSiz!=aMagnSiz) { aMagnSiz=rSiz; SnapMove(); } }
	const Size& GetSnapMagnetic() const { return aMagnSiz; }
	void SetSnapMagneticPixel(USHORT nPix) { nMagnSizPix=nPix; }
	USHORT GetSnapMagneticPixel() const { return nMagnSizPix; }

	// RecalcLogicSnapMagnetic muss bei jedem Wechsel des OutputDevices
	// sowie bei jedem Wechsel des MapModes gerufen werden!
	void RecalcLogicSnapMagnetic(const OutputDevice& rOut) { SetSnapMagnetic(rOut.PixelToLogic(Size(nMagnSizPix,nMagnSizPix))); }
	void SetActualWin(const OutputDevice* pWin) { SdrPaintView::SetActualWin(pWin); if (pWin!=NULL) RecalcLogicSnapMagnetic(*pWin); }

	// Auf die View bezogene Koordinaten!
	// Rueckgabewerte sind SDRSNAP_NOTSNAPPED,SDRSNAP_XSNAPPED,
	// SDRSNAP_YSNAPPED oder SDRSNAP_XYSNAPPED
	USHORT SnapPos(Point& rPnt, const SdrPageView* pPV) const;
	Point GetSnapPos(const Point& rPnt, const SdrPageView* pPV) const;
	USHORT SnapRect(const Rectangle& rRect, const SdrPageView* pPV, long& rDX, long& rDY) const;
	void CheckSnap(const Point& rPt, const SdrPageView* pPV,
		long& nBestXSnap, long& nBestYSnap, BOOL& bXSnapped, BOOL& bYSnapped) const;
	void SnapMove();

	// Alle Fangeinstellungen sind Persistent.
	BOOL IsSnapEnabled() const { return bSnapEnab; }
	BOOL IsGridSnap() const { return bGridSnap; } // Fang auf Rastergitter
	BOOL IsBordSnap() const { return bBordSnap; } // Fang auf Seitenraender
	BOOL IsHlplSnap() const { return bHlplSnap; } // Fang auf Hilfslinien
	BOOL IsOFrmSnap() const { return bOFrmSnap; } // Fang auf LogFram von umgebenden Zeichenobjekten
	BOOL IsOPntSnap() const { return bOPntSnap; } // Fang auf ausgepraegte Punkte von umgebenden Zeichenobjekten
	BOOL IsOConSnap() const { return bOConSnap; } // Fang auf Konnektoren der Zeichenobjekte
	void SetSnapEnabled(BOOL bOn) { bSnapEnab=bOn; SnapMove(); }
	void SetGridSnap(BOOL bOn) { bGridSnap=bOn; SnapMove(); }
	void SetBordSnap(BOOL bOn) { bBordSnap=bOn; SnapMove(); }
	void SetHlplSnap(BOOL bOn) { bHlplSnap=bOn; SnapMove(); }
	void SetOFrmSnap(BOOL bOn) { bOFrmSnap=bOn; SnapMove(); }
	void SetOPntSnap(BOOL bOn) { bOPntSnap=bOn; SnapMove(); }
	void SetOConSnap(BOOL bOn) { bOConSnap=bOn; SnapMove(); }

	// Normalerweise werden beim Move-Dragging von Zeichenobjekten alle
	// 4 Ecken des Object-SnapRects gefangen. Folgende Einstellmoeglichkeit,
	// wenn man nur auf die linke obere Ecke fangen will (z.B. DialogEditor):
	// Persistent, Default=FALSE.
	void SetMoveSnapOnlyTopLeft(BOOL bOn) { bMoveSnapOnlyTopLeft=bOn; SnapMove(); }
	BOOL IsMoveSnapOnlyTopLeft() const { return bMoveSnapOnlyTopLeft; }

	// Hilfslinien fixiert (nicht verschiebbar)
	// Persistent, Default=FALSE.
	BOOL IsHlplFixed() const { return bHlplFixed; }
	void SetHlplFixed(BOOL bOn) { bHlplFixed=bOn; }

	BOOL IsMoveMFrmSnap() const { return bMoveMFrmSnap; } // Fang des LogFram aller markierten Objekte
	BOOL IsMoveOFrmSnap() const { return bMoveOFrmSnap; } // Fang aller LogFram der markierten Objekte
	BOOL IsMoveOPntSnap() const { return bMoveOPntSnap; } // Fang ausgepraegter Punkte der markierten Objekte
	BOOL IsMoveOConSnap() const { return bMoveOConSnap; } // Fang der Konnektoren der markierten Objekte

	void SetMoveMFrmSnap(BOOL bOn) { bMoveMFrmSnap=bOn; SnapMove(); }
	void SetMoveOFrmSnap(BOOL bOn) { bMoveOFrmSnap=bOn; SnapMove(); }
	void SetMoveOPntSnap(BOOL bOn) { bMoveOPntSnap=bOn; SnapMove(); }
	void SetMoveOConSnap(BOOL bOn) { bMoveOConSnap=bOn; SnapMove(); }

	BOOL BegSetPageOrg(const Point& rPnt, OutputDevice* pOut=NULL, short nMinMov=0);
	void MovSetPageOrg(const Point& rPnt);
	BOOL EndSetPageOrg();
	void BrkSetPageOrg();
	BOOL IsSetPageOrg() const { return bSetPageOrg; }

	// HitTest. Bei TRUE steht in rnHelpLineNum die Nummer der Hilfslinie und in rpPV
	// die zugehoerige PageView.
	BOOL PickHelpLine(const Point& rPnt, short nTol, const OutputDevice& rOut, USHORT& rnHelpLineNum, SdrPageView*& rpPV) const;
	BOOL PickHelpLine(const Point& rPnt, const OutputDevice& rOut, USHORT& rnHelpLineNum, SdrPageView*& rpPV) const { return PickHelpLine(rPnt,-2,rOut,rnHelpLineNum,rpPV); }

	// Verschieben einer vorhandenen Hilfslinie. nHelpLineNum und pPV von PickHelpLine verwenden.
	BOOL BegDragHelpLine(USHORT nHelpLineNum, SdrPageView* pPV, OutputDevice* pOut=NULL, short nMinMov=-3);

	// Interaktives einfuegen einer neuen Hilfslinie
	BOOL BegDragHelpLine(const Point& rPnt, SdrHelpLineKind eNewKind, OutputDevice* pOut=NULL, short nMinMov=0);
	const SdrHelpLine& GetDraggedHelpLine() const { return aDragHelpLine; }
	SdrHelpLineKind GetDraggedHelpLineKind() const { return aDragHelpLine.GetKind(); }

	// Folgende 2 Methoden sind nur gueltig beim Verschieben einer
	// vorhandenen Hilfslinie oder evtl. nach EndDragHelpLine
	USHORT GetDraggedHelpLineIndex() const { return nDragHelpLineNum; }
	SdrPageView* GetDraggedHelpLinePageView() const { return pDragHelpLinePV; }

	// Aendern des Hilfslinientyps waerend des draggens
	void SetDraggedHelpLineKind(SdrHelpLineKind eNewKind);
	void MovDragHelpLine(const Point& rPnt);
	BOOL EndDragHelpLine();
	void BrkDragHelpLine();
	BOOL IsDragHelpLine() const { return bDragHelpLine; }

	// SnapAngle ist fuer Winkel im Kreis, RotateDragging, ...
	// Der Winkelfang wird unterdrueckt, wenn er mit
	// durch SetAngleSnapEnabled(FALSE) ausgeschaltet ist.
	// Der Winkelfang ist unabhaengig vom Koordinatenfang
	// und somit von der Einstellung IsSnapEnabled()
	// Es sollten nur Werte angegeben werden fuer die gilt:
	//     36000 modulu nWink = 0
	// Implementiert fuer:
	// - Rotate (Dragging)
	// - Shear (Dragging)
	// - Kreisbogen/-sektor/-abschnitt Winkel (Create und Dragging)
	// Persistent.
	void SetAngleSnapEnabled(BOOL bOn) { bAngleSnapEnab=bOn; SnapMove(); }
	BOOL IsAngleSnapEnabled() const { return bAngleSnapEnab; }
	void SetSnapAngle(long nWink) { nSnapAngle=nWink;   SnapMove(); }
	long GetSnapAngle() const { return nSnapAngle; }

	// Ortho hat je nach Kontext verschiedene Effekte:
	// - Create
	//   - Linien werden nur im 45deg Raster zugelassen
	//   - Statt Rechtecke werden Quadrate erzeugt
	//   - Statt Ellipsen werden Kreise erzeugt
	// - Dragging
	//   - allgemeines Dragging
	//     - Move nur Hor, Vert oder 45deg
	//     - Resize proportional
	//     - Mirror: nichts
	//     - Shear ohne Resize
	//     - Crook ohne Resize
	//   - verschieben der Handles
	//     - Spiegelachse nur 45deg Raster
	//   - Objekteigenes Dragging
	//     - Rechteck Eckenradius: nichts
	//     - Kreisobjekt Winkel: nichts
	//     - Linie behaelt beim Draggen ihren Winkel bei und wird nur    (ni)
	//       verlaengert bzw. verkuerzt.
	// Defaultmaessig ist Ortho ausgeschaltet. Persistent.
	void SetOrtho(BOOL bOn) { bOrtho=bOn; } // unvollstaendig
	BOOL IsOrtho() const { return bOrtho; }

	// BigOrtho hat nur Relevanz wenn Ortho eingeschaltet ist.
	// Beispiel: Ein Rechteck wird mit eingeschaltetem Ortho (also ein Quadrat)
	//   erzeugt und die Maus wurde dabei vom Nullpunkt zu den Koordinaten
	//   (80,30) gedraggt. Dann stuenden nun 2 Alternativen zur Bestimmung der
	//   Kantenlaenge des Quadrats zur Wahl: 30 und 80.
	//   Die normale Ortho-Funktuionalitaet brachte hierbei ein Quadrat mit
	//   Kantenlaenge 30 (also immer die kleinere Groesse). Bei hinzugeschal-
	//   tetem BigOrtho bekaeme man dagegen ein Quadrat der Kantenlaenge 80.
	// Gleiches gilt auch fuer Resize.
	// Defaultmaessig ist BigOrtho eingeschaltet. Persistent.
	void SetBigOrtho(BOOL bOn) { bBigOrtho=bOn; SnapMove(); }
	BOOL IsBigOrtho() const { return bBigOrtho; }

	// bei MoveOnlyDragging=TRUE wird bei Resize/Rotate/Shear/Mirror/Crook
	// nur das Zentrum der markierten Objekte transformiert. Groesse, Form
	// und Drehwinkel der Objekte bleiben erhalten, nur ihre Positionen
	// aendern sich. Persistent. Default=FALSE. (ni)
	void SetMoveOnlyDragging(BOOL bOn) { bMoveOnlyDragging=bOn; }
	BOOL IsMoveOnlyDragging() const { return bMoveOnlyDragging; }

	// Slant anstelle von Shear anwenden. Persistent. Default=FALSE.
	void SetSlantButShear(BOOL bOn) { bSlantButShear=bOn; SnapMove(); }
	BOOL IsSlantButShear() const { return bSlantButShear; }

	// Objekte bei Crook nicht verzerren. Persistent. Default=FALSE. (ni)
	void SetCrookNoContortion(BOOL bOn) { bCrookNoContortion=bOn; SnapMove(); }
	BOOL IsCrookNoContortion() const { return bCrookNoContortion; }

	// Crook-Modus. Persistent. Default=SDRCROOK_ROTATE. (ni)
	void SetCrookMode(SdrCrookMode eMode) { eCrookMode=eMode; SnapMove(); }
	SdrCrookMode GetCrookMode() const { return eCrookMode; }

	// Special fuer IBM: Beim Draggen eines Polygonpunkts wird dieser
	// geloescht, wenn seine beiden angrenzenden Linien eh' fast eine
	// durchgehende Linie sind.
	void SetEliminatePolyPoints(BOOL bOn) { bEliminatePolyPoints=bOn; SnapMove(); }
	BOOL IsEliminatePolyPoints() const { return bEliminatePolyPoints; }
	void SetEliminatePolyPointLimitAngle(long nAngle) { nEliminatePolyPointLimitAngle=nAngle; SnapMove(); }
	long GetEliminatePolyPointLimitAngle() const { return nEliminatePolyPointLimitAngle; }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Begriffsdefinition:
//   - Etwas fangen=Gefangen werden kann z.B. der Mauszeiger oder die z.Zt. im
//     Drag befindlichen markierten Objekte.
//   - Auf etwas fangen=Man kann z.B. auf das Grid oder auf Hilfslinien fangen.
//
// Grundsaetzlich wird nur gefangen auf sichtbare Elemente (-> Border,
// Hilfslinien, Konnektoren; Ausnahme: Grid). Ebenso koennen nur sichtbare
// Elemente gefangen werden (->Konnektoren).
//
// Auf's Grid wird immer erst dann gefangen, wenn nix Anderes in der Naehe
// (->Magnetic) ist.
//
// Der "Cursor" (also der Mauszeiger) beim Erzeugen von Objekten, beim Draggen
// von Polygonpunkten, ... wird immer auf allen eingeschalteten Fangalternativen
// gefangen (max 6).
//
// Beim Verschieben markierter Objekte ist das etwas anders. Statt des einen
// Mauscursors gibt es hier 4 Alternativen an den markierten Objekten, die
// gefangen werden koennen:
//   1. die logisch-umschliessenden Rahmen der einzelnen Objekte
//   2. der logisch-umschliessende Rahmen aller markierten Objekte
//   3. ausgezeichnete Punkte der markierten Objekte (Polygonpunkte, ...)
//   4. die Konnektoren der markierten Objekte
// Da 1. und 2. einander ausschliessen (2. ist eine Verfeinerung von 1.)
// bleiben 3 voneinander unabhaengige Alternativen. Bei 6. Moeglichkeiten auf
// die gefangen werden kann kaeme man auf max. 18 Kombinationsmoeglichkeiten!
// Deshalb werden folgende Vereinfachungen festgelegt:
//   1. Konnektoren fangen sich nur auf Konnektoren.
// Verbleiben also nun noch max. 2x5+1=11 Fangkombinationen beim MoveDrag:
//   1-3.  umschliessende(r) Rahmen auf Grid/Border/Hilfslinien
//   4.    umschliessende(r) Rahmen auf ausgezeichnete Objektpunkte
//   5.    umschliessende(r) Rahmen auf umschliessenden Rahmen
//   6-8.  ausgezeichnete Punkte auf Grid/Border/Hilfslinien
//   7.    ausgezeichnete Punkte auf ausgezeichnete Objektpunkte
//   8-10. ausgezeichnete Punkte auf umschliessenden Rahmen
//   11.   Konnektoren auf Konnektoren
// Beim MouseMove-Event im DragMove werden also diese bis zu max. 11 moeglichen
// Alternativen durchgetestet und die mit dem gerigsten Korrekturaufwand
// vollzogen.
//
// Beim Resize, ... wird immer nur der logisch-umschliessende Rahmen der
// markierten Objekte gefangen.
//
////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //_SVDSNPV_HXX

