[Date Prev][Date Next][Thread Prev][Thread Next][Thread Index]

[XaraXtreme-commits] Commit Complete



Commit by  : phil
Repository : xara
Revision   : 1472
Date       : Tue Jul 18 20:49:25 BST 2006

Changed paths:
   M /Trunk/XaraLX/Kernel/nodetext.cpp
   M /Trunk/XaraLX/Kernel/nodetxtl.cpp
   M /Trunk/XaraLX/Kernel/nodetxtl.h
   M /Trunk/XaraLX/Kernel/rulers.cpp
   M /Trunk/XaraLX/tools/textinfo.cpp
   M /Trunk/XaraLX/tools/textinfo.h
   M /Trunk/XaraLX/wxOil/oilruler.cpp

MartinW's margin support update


Diff:
Index: Trunk/XaraLX/tools/textinfo.cpp
===================================================================
--- Trunk/XaraLX/tools/textinfo.cpp	(revision 1471)
+++ Trunk/XaraLX/tools/textinfo.cpp	(revision 1472)
@@ -196,9 +196,10 @@
 														// that we need to find common attributes for
 // cached bitmap sizes
 UINT32 TextInfoBarOp::TabBitmapWidth;
-UINT32 TextInfoBarOp::TabBitmapHeight;
 UINT32 TextInfoBarOp::CurrentTabButtonWidth;
-UINT32 TextInfoBarOp::CurrentTabButtonHeight;
+UINT32 TextInfoBarOp::LeftMarginBitmapWidth;
+UINT32 TextInfoBarOp::LeftMarginBitmapHeight;
+UINT32 TextInfoBarOp::RightMarginBitmapWidth;
 
 FontDropDown	*TextInfoBarOp::NameDropDown = NULL;	// Font name drop-down list support for the font list and
 
@@ -435,10 +436,15 @@
 	// the sizes into the mouse click detection code in OnRulerClick())
 	// first, the size of the "current tab type" button - we ask for the left tab variant,
 	// but they should all be the same size
-	if (ok) ok = FindBitmapSize(_R(clefttab), &CurrentTabButtonWidth, &CurrentTabButtonHeight);
+	UINT32 Dummy;
+	if (ok) ok = FindBitmapSize(_R(clefttab), &CurrentTabButtonWidth, &Dummy);
 	// find out about the size of tab stop blobs - we ask for the left tab variant, but they
 	// should all be the same size
-	if (ok) ok = FindBitmapSize(_R(lefttab), &TabBitmapWidth, &TabBitmapHeight);
+	if (ok) ok = FindBitmapSize(_R(lefttab), &TabBitmapWidth, &Dummy);
+	// find out about the width and height of the first indent blob
+	if (ok) ok = FindBitmapSize(_R(leftmar), &LeftMarginBitmapWidth, &LeftMarginBitmapHeight);
+	// find out about the width of the left/right margin blobs
+	if (ok) ok = FindBitmapSize(_R(rightmar), &RightMarginBitmapWidth, &Dummy);	
 	return ok;
 }
 
@@ -3009,11 +3015,8 @@
 
 void TextInfoBarOp::TabStopDragStarting(TabStopDragType TheType)
 {
-	if (TheType == DragTabStop || TheType == DragNew)
-	{
-		TRACEUSER("wuerthne", _T("tab stop drag starting"));
-		RulerData.TabStopDragRunning = TRUE;
-	}
+	RulerData.TabStopDragRunning = TRUE;
+	RulerData.CurrentDragType = TheType;
 }
 
 /********************************************************************************************
@@ -3075,17 +3078,26 @@
 {
 	if (!pRuler->IsHorizontal()) return;
 
-	if (RulerData.IsLeftMarginValid)
-		pRuler->DrawBitmap(RulerData.LeftMargin, _R(leftmar));
-	else
-		pRuler->DrawBitmap(0, _R(gleftmar));
+	if (!(RulerData.TabStopDragRunning && RulerData.CurrentDragType == DragLeftMargin))
+	{
+		// not currently dragging the left margin, so display it if it is the same across
+		// the selection, else show the greyed out margin icon at the origin
+		if (RulerData.IsLeftMarginValid)
+			pRuler->DrawBitmap(RulerData.LeftMargin, _R(leftmar));
+		else
+			pRuler->DrawBitmap(0, _R(gleftmar));
+	}
 
-	if (RulerData.IsFirstIndentValid)
-		pRuler->DrawBitmap(RulerData.FirstIndent, _R(firstind));
-	else
-		pRuler->DrawBitmap(0, _R(gfirstind));
+	if (!(RulerData.TabStopDragRunning && RulerData.CurrentDragType == DragFirstIndent))
+	{
+		if (RulerData.IsFirstIndentValid)
+			pRuler->DrawBitmap(RulerData.FirstIndent, _R(firstind));
+		else
+			pRuler->DrawBitmap(0, _R(gfirstind));
+	}
 
-	if (RulerData.CurrentRulerSectionWidth != -1)
+	if (RulerData.CurrentRulerSectionWidth != -1
+		&& !(RulerData.TabStopDragRunning && RulerData.CurrentDragType == DragRightMargin))
 	{
 		// we only draw a right margin if we have a fixed formatting width
 		if (RulerData.IsRightMarginValid)
@@ -3119,7 +3131,8 @@
 			LastPos = (*it).GetPosition();
 		}
 
-		if (!RulerData.TabStopDragRunning)
+		if (!(RulerData.TabStopDragRunning &&
+			  (RulerData.CurrentDragType == DragNew || RulerData.CurrentDragType == DragTabStop)))
 		{
 			TRACEUSER("wuerthne", _T("redraw implicit tab stops"));
 			// draw greyed out left align tab stops at equidistant positions beyond the last defined
@@ -3187,6 +3200,7 @@
 								 Spread* pSpread, RulerBase* pRuler)
 {
 	if (!pRuler->IsHorizontal()) return FALSE;
+	TRACEUSER("wuerthne", _T("ruler click (%d,%d)"), PointerPos.x, PointerPos.y);
 	if (Click == CLICKTYPE_SINGLE)
 	{
 		// check whether the user has clicked on our homegrown "current tab" button
@@ -3255,41 +3269,83 @@
 		// to the right have priority
 		Document::SetSelectedViewAndSpread(pDocView->GetDoc(), pDocView, pSpread);
 		
-		INT32 Index = 0;
 		INT32 MatchedIndex = -1;
-		for (TxtTabStopIterator it = RulerData.pShownRuler->begin(); it != RulerData.pShownRuler->end(); ++it)
+		TxtTabStop DraggedTabStop(LeftTab, 0);
+		if (RulerData.IsRulerValid)
 		{
-			MILLIPOINT Pos = (*it).GetPosition();
-			if (PointerPos.x >= Pos - MILLIPOINT(TabBitmapWidth / 2 * PixelSize)
-				&& PointerPos.x <= Pos + MILLIPOINT(TabBitmapWidth / 2 * PixelSize))
+			INT32 Index = 0;
+			for (TxtTabStopIterator it = RulerData.pShownRuler->begin(); it != RulerData.pShownRuler->end(); ++it)
 			{
-				TRACEUSER("wuerthne", _T("hit tab no %d"), Index);
-				MatchedIndex = Index;
+				MILLIPOINT Pos = (*it).GetPosition();
+				if (PointerPos.x >= Pos - MILLIPOINT(TabBitmapWidth / 2 * PixelSize)
+					&& PointerPos.x <= Pos + MILLIPOINT(TabBitmapWidth / 2 * PixelSize))
+				{
+					TRACEUSER("wuerthne", _T("hit tab no %d"), Index);
+					MatchedIndex = Index;
+				}
+				Index++;
 			}
-			Index++;
+			
+			if (MatchedIndex != -1)
+			{
+				// delete the tab stop from the shown ruler list
+				Index = MatchedIndex;
+				TxtTabStopIterator it = RulerData.pShownRuler->begin();
+				while(it != RulerData.pShownRuler->end() && Index--) ++it;
+				if (it != RulerData.pShownRuler->end())
+				{
+					DraggedTabStop = *it;
+					RulerData.pShownRuler->erase(it);
+				}
+				else
+				{
+					// cannot really happen, but exit gracefully - we still claim the click
+					return TRUE;
+				}
+			}
 		}
+		TabStopDragType DragType = (MatchedIndex == -1) ? DragNew : DragTabStop;
 		
-		TxtTabStop DraggedTabStop(LeftTab, 0);
-		if (MatchedIndex != -1)
+		if (MatchedIndex == -1)
 		{
-			// delete the tab stop from the shown ruler list
-			Index = MatchedIndex;
-			TxtTabStopIterator it = RulerData.pShownRuler->begin();
-			while(it != RulerData.pShownRuler->end() && Index--) ++it;
-			if (it != RulerData.pShownRuler->end())
+			// no tab stop hit, but maybe the margin markers?
+			MILLIPOINT LeftMarginPos = RulerData.IsLeftMarginValid ? RulerData.LeftMargin : 0;
+			MILLIPOINT FirstIndentPos = RulerData.IsFirstIndentValid ? RulerData.FirstIndent : 0;
+			MILLIPOINT RightMarginPos = RulerData.CurrentRulerSectionWidth
+											- (RulerData.IsRightMarginValid ? RulerData.RightMargin : 0);
+
+			// We test for the left margin first because we check the vertical position to distinguish
+			// between left margin and first indent drags even when they are at the same position
+			if (PointerPos.x >= LeftMarginPos - MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize)
+				&& PointerPos.x <= LeftMarginPos + MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize)
+				&& PointerPos.y <= MILLIPOINT(LeftMarginBitmapHeight * PixelSize))
 			{
-				DraggedTabStop = *it;
-				RulerData.pShownRuler->erase(it);
+				TRACEUSER("wuerthne", _T("drag left margin"));
+				DragType = DragLeftMargin;
 			}
 			else
 			{
-				// cannot really happen, but exit gracefully - we still claim the click
-				return TRUE;
+				// we do not check the vertical position for other margin drags - if there was a tab stop
+				// at the same position it got priority anyway
+				if (PointerPos.x >= FirstIndentPos - MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize)
+					&& PointerPos.x <= FirstIndentPos + MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize))
+				{
+					TRACEUSER("wuerthne", _T("drag left margin"));
+					DragType = DragFirstIndent;
+				}
+				else
+				{
+					if (PointerPos.x >= RightMarginPos - MILLIPOINT(RightMarginBitmapWidth / 2 * PixelSize)
+						&& PointerPos.x <= RightMarginPos + MILLIPOINT(RightMarginBitmapWidth / 2 * PixelSize))
+					{
+						TRACEUSER("wuerthne", _T("drag right margin"));
+						DragType = DragRightMargin;
+					}
+				}
 			}
 		}
-		TabStopDragType DragType = (MatchedIndex == -1) ? DragNew : DragTabStop;
-		
-		if (DragType == DragNew && InHighlightSection || DragType != DragNew)
+
+		if (InHighlightSection || DragType != DragNew)
 		{
 			String_256 OpToken(OPTOKEN_TABSTOPDRAG);
 			TRACEUSER("wuerthne", _T("starting drag"));
@@ -3371,6 +3427,7 @@
 	// let us forget about it
 	RulerData.pNewRuler = NULL;
 }
+
 /********************************************************************************************
 
 >	void TextInfoBarOp::DoApplyShownRuler()
@@ -3397,10 +3454,75 @@
 	// just to avoid confusion - OnFieldChange has taken control of the object, so
 	// let us forget about it
 	RulerData.pNewRuler = NULL;
+	// we just applied what we had in pShownRuler, so UpdateRuler() will think that
+	// nothing has changed - but we want the implicit tabs to reappear
+	ForceRulerRedraw();
 }
 
 /********************************************************************************************
 
+>	void TextInfoBarOp::DoChangeLeftMargin(MILLIPOINT Ordinate)
+
+	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+	Created:	18/07/06
+	Inputs:     Ordinate - the new position
+	Purpose:	Apply the changed left margin
+
+********************************************************************************************/
+
+void TextInfoBarOp::DoChangeLeftMargin(MILLIPOINT Ordinate)
+{
+	RulerData.IsLeftMarginValid = TRUE;
+	RulerData.LeftMargin = Ordinate;
+	OnFieldChange(LeftMarginA);
+	ForceRulerRedraw();
+}
+
+/********************************************************************************************
+
+>	void TextInfoBarOp::DoChangeFirstIndent(MILLIPOINT Ordinate)
+
+	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+	Created:	18/07/06
+	Inputs:     Ordinate - the new position
+	Purpose:	Apply the changed first line indent
+
+********************************************************************************************/
+
+void TextInfoBarOp::DoChangeFirstIndent(MILLIPOINT Ordinate)
+{
+	RulerData.IsFirstIndentValid = TRUE;
+	RulerData.FirstIndent = Ordinate;
+	OnFieldChange(FirstIndentA);
+	ForceRulerRedraw();
+}
+
+/********************************************************************************************
+
+>	void TextInfoBarOp::DoChangeRightMargin(MILLIPOINT Ordinate)
+
+	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+	Created:	18/07/06
+	Inputs:     Ordinate - the new position
+	Purpose:	Apply the changed right margin
+
+********************************************************************************************/
+
+void TextInfoBarOp::DoChangeRightMargin(MILLIPOINT Ordinate)
+{
+	// the right margin is actually an indent, i.e., an offset from the column width (otherwise
+	// we could not have a default attribute that makes sense and text objects with different
+	// widths would have to have different right margin attributes)
+	RulerData.IsRightMarginValid = TRUE;
+	// we allow the margin to become negative, i.e., to be located to the right of the
+	// column width
+	RulerData.RightMargin = RulerData.CurrentRulerSectionWidth - Ordinate;
+	OnFieldChange(RightMarginA);
+	ForceRulerRedraw();
+}
+
+/********************************************************************************************
+
 >	INT32 TextInfoBarOp::GetLogicalStoryWidth(TextStory* pStory)
 
 	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
@@ -3457,8 +3579,11 @@
 		// there is a focus story, so the ruler should adapt to it
 		TRACEUSER("wuerthne", _T("Focus story present"));
 		ShouldWeClaimRuler = TRUE;
-		DocRect StoryBounds=pFocusStory->GetBoundingRect();
-		DocCoord TopLeft(StoryBounds.lo.x, StoryBounds.hi.y);
+		// DocRect StoryBounds=pFocusStory->GetBoundingRect();
+		// DocCoord TopLeft(StoryBounds.lo.x, StoryBounds.hi.y);
+		const Matrix* pStoryMatrix = pFocusStory->GetpStoryMatrix();
+		DocCoord TopLeft(0,0);
+		pStoryMatrix->transform(&TopLeft);
 		UserCoord UserTopLeft = TopLeft.ToUser(pFocusStory->FindParentSpread());
 		RulerOrigin = UserTopLeft.x;
 		StoryWidth = GetLogicalStoryWidth(pFocusStory);
@@ -3472,8 +3597,10 @@
 			if (IS_A(pNode, TextStory))
 			{
 				TextStory* pStory = (TextStory*)pNode;
-				DocRect StoryBounds=pStory->GetBoundingRect();
-				DocCoord TopLeft(StoryBounds.lo.x, StoryBounds.hi.y);
+
+				const Matrix* pStoryMatrix = pStory->GetpStoryMatrix();
+				DocCoord TopLeft(0,0);
+				pStoryMatrix->transform(&TopLeft);
 				UserCoord UserTopLeft = TopLeft.ToUser(pStory->FindParentSpread());
 				
 				if (!ShouldWeClaimRuler || UserTopLeft.x < RulerOrigin)
@@ -3760,51 +3887,46 @@
 		UserPos.x -= TextInfoBarOp::GetRulerOrigin();
 		Ordinate = UserPos.x;
 		TRACEUSER("wuerthne", _T("with success at %d"), Ordinate);
-
-		if (m_pParam->m_DragType == DragNew)
+		
+		switch(m_pParam->m_DragType)
 		{
-			if (IsMouseOverRuler())
-			{
-				TextInfoBarOp::DoAddTabStop(Ordinate);
-			}
-			else
-			{
-				// do nothing (apart from redrawing the ruler bar, so the implicit
-				// tabs will be displayed again)
-				TextInfoBarOp::ForceRulerRedraw();
-			}
+			case DragNew:
+				if (IsMouseOverRuler())
+				{
+					TextInfoBarOp::DoAddTabStop(Ordinate);
+				}
+				else
+				{
+					// do nothing (apart from redrawing the ruler bar, so the implicit
+					// tabs will be displayed again)
+					TextInfoBarOp::ForceRulerRedraw();
+				}
+				break;
+			case DragTabStop:
+				if (IsMouseOverRuler())
+				{
+					TxtTabStop NewTabStop(m_pParam->m_DraggedTabStop);
+					NewTabStop.SetPosition(Ordinate);
+					TextInfoBarOp::DoAddTabStop(NewTabStop);
+				}
+				else
+				{
+					// delete the tab stop; we can do that by simply applying the shown
+					// ruler - we have removed the tab stop from the shown ruler when the
+					// drag started
+					TextInfoBarOp::DoApplyShownRuler();
+				}
+				break;
+			case DragLeftMargin:
+				TextInfoBarOp::DoChangeLeftMargin(Ordinate);
+				break;
+			case DragFirstIndent:
+				TextInfoBarOp::DoChangeFirstIndent(Ordinate);
+				break;
+			case DragRightMargin:
+				TextInfoBarOp::DoChangeRightMargin(Ordinate);
+				break;
 		}
-		else if (m_pParam->m_DragType == DragTabStop)
-		{
-			if (IsMouseOverRuler())
-			{
-				TxtTabStop NewTabStop(m_pParam->m_DraggedTabStop);
-				NewTabStop.SetPosition(Ordinate);
-				TextInfoBarOp::DoAddTabStop(NewTabStop);
-			}
-			else
-			{
-				// delete the tab stop; we can do that by simply applying the shown
-				// ruler - we have removed the tab stop from the shown ruler when the
-				// drag started
-				TextInfoBarOp::DoApplyShownRuler();
-			}
-		}
-
-#if 0
-		if (pDraggedGuideline != NULL)
-		{
-			if (IsMouseOverRuler())
-			{
-				UndoIDS = _R(IDS_OPDELETEGUIDELINE);
-				Success = DoDeleteGuideline(pDraggedGuideline);
-			}
-			else
-				Success = DoTranslateGuideline(pDraggedGuideline,Ordinate);
-		}
-		else
-			Success = !IsMouseOverRuler() && DoNewGuideline(NULL,NEXT,Type,Ordinate);
-#endif
 	}
 
 	// End the Drag
Index: Trunk/XaraLX/tools/textinfo.h
===================================================================
--- Trunk/XaraLX/tools/textinfo.h	(revision 1471)
+++ Trunk/XaraLX/tools/textinfo.h	(revision 1472)
@@ -155,6 +155,18 @@
 
 /********************************************************************************************
 
+>	enum TabStopDragType
+
+	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+	Created:	13/07/06
+	Purpose:	Different types of drag operations on the ruler bar
+
+********************************************************************************************/
+
+enum TabStopDragType { DragNew, DragTabStop, DragLeftMargin, DragRightMargin, DragFirstIndent };
+
+/********************************************************************************************
+
 >	class TextRulerBarData:
 
 	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
@@ -194,6 +206,7 @@
 	INT32 CurrentRulerOrigin;           // origin of our ruler section (in user space)
 	INT32 CurrentRulerSectionWidth;     // width of our ruler section (-1 for infinite)
 	BOOL TabStopDragRunning;
+	TabStopDragType CurrentDragType;
 };
 
 /********************************************************************************************
@@ -238,18 +251,6 @@
 
 /********************************************************************************************
 
->	enum TabStopDragType
-
-	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
-	Created:	13/07/06
-	Purpose:	Different types of drag operations on the ruler bar
-
-********************************************************************************************/
-
-enum TabStopDragType { DragNew, DragTabStop, DragLeftMargin, DragRightMargin, DragFirstIndent };
-
-/********************************************************************************************
-
 >	class TextInfoBarOp : public InformationBarOp
 
 	Author:		Chris_Parks (Xara Group Ltd) <camelotdev@xxxxxxxx>
@@ -323,7 +324,11 @@
 	static void DoAddTabStop(MILLIPOINT Position);
 	static void DoAddTabStop(TxtTabStop NewTabStop);
 	static void DoApplyShownRuler();
+	static void DoChangeLeftMargin(MILLIPOINT Ordinate);
+	static void DoChangeRightMargin(MILLIPOINT Ordinate);
+	static void DoChangeFirstIndent(MILLIPOINT Ordinate);
 
+
 public:
 // the current infobar object - allow static member access
 	static InformationBarOp * pTextInfoBar;
@@ -433,10 +438,11 @@
 	static CommonAttrSet CommonAttrsToFindSet; 
 
 	// cached bitmap sizes
+	static UINT32 CurrentTabButtonWidth;
 	static UINT32 TabBitmapWidth;
-	static UINT32 TabBitmapHeight;
-	static UINT32 CurrentTabButtonWidth;
-	static UINT32 CurrentTabButtonHeight;
+	static UINT32 LeftMarginBitmapWidth;
+	static UINT32 LeftMarginBitmapHeight;
+	static UINT32 RightMarginBitmapWidth;
 };
 	
 
Index: Trunk/XaraLX/Kernel/nodetxtl.cpp
===================================================================
--- Trunk/XaraLX/Kernel/nodetxtl.cpp	(revision 1471)
+++ Trunk/XaraLX/Kernel/nodetxtl.cpp	(revision 1472)
@@ -377,6 +377,7 @@
 	NodeCopy->mLineSpacing    = mLineSpacing;
 	NodeCopy->mLineSpaceRatio = mLineSpaceRatio;
 	NodeCopy->mLeftMargin = mLeftMargin;
+	NodeCopy->mFirstIndent = mFirstIndent;
 	NodeCopy->mRightMargin = mRightMargin;
 	NodeCopy->mpRuler = mpRuler;
 
@@ -717,25 +718,41 @@
 	SetLineSpacing(   pFormatRegion->GetLineSpacing());
 	SetLineSpaceRatio(pFormatRegion->GetLineSpaceRatio());
 
+	SetParaLeftMargin(pFormatRegion->GetLeftMargin());
+	SetParaFirstIndent(pFormatRegion->GetFirstIndent());
+	SetParaRightMargin(pFormatRegion->GetRightMargin());
+	SetRuler(pFormatRegion->GetRuler());
+	return TRUE;
+}
+
+/********************************************************************************************
+>	MILLIPOINT TextLine::GetEffectiveLeftMargin()
+
+	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+	Created:	18/07/06
+	Inputs:		-
+	Returns:	the left margin value to use
+	Purpose:	Select the left margin or first indent value depending on whether this is
+				the first line in the paragraph
+********************************************************************************************/
+
+MILLIPOINT TextLine::GetEffectiveLeftMargin()
+{
 	// we need to find out whether this is the first line in the paragraph, so we know
 	// whether we need to use FirstLineIndent or LeftMargin
+
 	TextLine* pPrevLine = FindPrevLine();
 	if (pPrevLine==NULL || pPrevLine->FindEOLNode() != NULL)
 	{
 		// first line in paragraph
-		SetParaLeftMargin(pFormatRegion->GetFirstIndent());
+		return mFirstIndent;
 	}
 	else
 	{
-		// not first line, so use normal left margin
-		SetParaLeftMargin(pFormatRegion->GetLeftMargin());
+		return mLeftMargin;
 	}
-	SetParaRightMargin(pFormatRegion->GetRightMargin());
-	SetRuler(pFormatRegion->GetRuler());
-	return TRUE;
 }
 
-
 /********************************************************************************************
 >	BOOL TextLine::Format(TextStoryInfo* pStoryInfo)
 
@@ -758,7 +775,7 @@
 	MILLIPOINT PhysicalRightMargin  = pStoryInfo->StoryWidth - pStoryInfo->RightPathIndent;
 	BOOL       WordWrapping = pStoryInfo->WordWrapping;
 	MILLIPOINT RightMargin = PhysicalRightMargin - mRightMargin;
-	MILLIPOINT LeftMargin = PhysicalLeftMargin + mLeftMargin;
+	MILLIPOINT LeftMargin = PhysicalLeftMargin + GetEffectiveLeftMargin();
 
 	// if word wrapping, and not text at a point, and undoably 'do'ing op, word wrap the line
 	MILLIPOINT WrapWidth = 0;
@@ -1405,7 +1422,7 @@
 	pLineInfo->NumChars        = NumCharsToLastNonSpace;
 	pLineInfo->NumSpaces       = NumSpacesToLastNonSpace;
 	pLineInfo->justification   = GetJustification();
-	pLineInfo->ParaLeftMargin  = GetParaLeftMargin();
+	pLineInfo->ParaLeftMargin  = GetEffectiveLeftMargin();
 	pLineInfo->ParaRightMargin = GetParaRightMargin();
 	pLineInfo->Ruler           = GetRuler();
 	return TRUE;
Index: Trunk/XaraLX/Kernel/rulers.cpp
===================================================================
--- Trunk/XaraLX/Kernel/rulers.cpp	(revision 1471)
+++ Trunk/XaraLX/Kernel/rulers.cpp	(revision 1472)
@@ -357,6 +357,7 @@
 	
 	// Find the spread in which the click happened
 	Spread *pSpread = pRulerPair->GetpSpread();
+	DocView* pDocView = pRulerPair->GetpDocView();
 
 	if (pSpread == NULL)
 	{
@@ -377,6 +378,14 @@
 	pSpread->DocCoordToSpreadCoord(&DocPos);
 	UserCoord UserPos = DocPos.ToUser(pSpread);
 
+	// the insignificant position on the ruler (in the narrow dimension) should not be converted to
+	// document coordinates - the result makes no sense, but we scale from OIL pixels to User coords
+	MILLIPOINT PixelSize = pDocView->GetScaledPixelWidth().MakeLong();
+	if (IsHorizontal())
+		UserPos.y = MILLIPOINT(PointerPos.y * PixelSize);
+	else
+		UserPos.x = MILLIPOINT(PointerPos.x * PixelSize);
+
 	// take the current tool ruler origin into account
 	UserCoord Offsets(0, 0);
 	if (Tool::GetCurrent())
Index: Trunk/XaraLX/Kernel/nodetext.cpp
===================================================================
--- Trunk/XaraLX/Kernel/nodetext.cpp	(revision 1471)
+++ Trunk/XaraLX/Kernel/nodetext.cpp	(revision 1472)
@@ -3863,8 +3863,37 @@
 	return NodeCopy;
 }
 
+/*******************************************************************************************
+>	BOOL HorizontalTab::ExportRender(RenderRegion* pRegion)
+
+ 	Author:		Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+ 	Created:	18/07/06
+ 	Inputs:		pRegion - points to the export render region
+	Returns:	TRUE if rendered OK (FALSE=>use normal rendering)
+ 	Purpose:	This function is called when the render function passes through this node
+ 				It outputs the	Text Object start and end tokens
+ 	See also:   KernCode::ExportRender, on which this routine is based
+********************************************************************************************/
 BOOL HorizontalTab::ExportRender(RenderRegion* pRegion)
 {
-	/*##*/
+	// a tab is exported as a horizontal kern code
+#if EXPORT_TEXT
+ 	if (pRegion->IsKindOf(CC_RUNTIME_CLASS(EPSRenderRegion)))
+	{
+		// Output any valid text attributes necessary
+		((EPSRenderRegion*)pRegion)->GetValidPathAttributes();
+		((EPSRenderRegion*)pRegion)->GetValidTextAttributes();
+
+		EPSExportDC *pDC=(EPSExportDC*)pRegion->GetRenderDC();
+
+		// Use illustrator 3.0 compatible token.
+		INT32 autokern = 0;
+		pDC->OutputValue(autokern);
+		pDC->OutputValue(GetCharWidth());
+ 		pDC->OutputToken(_T("Tk"));
+		pDC->OutputNewLine();
+		return TRUE;
+	}
+#endif
 	return FALSE;
 }
Index: Trunk/XaraLX/Kernel/nodetxtl.h
===================================================================
--- Trunk/XaraLX/Kernel/nodetxtl.h	(revision 1471)
+++ Trunk/XaraLX/Kernel/nodetxtl.h	(revision 1472)
@@ -235,7 +235,7 @@
 		CharPosOffset(_CharPosOffset),
 		ExtraOnChars(_ExtraOnChars), ExtraOnSpaces(_ExtraOnSpaces),
 		Width(Indent), ActiveTabType(LeftTab), ActiveTabPos(0), 
-		pLastTabVTN(NULL), AnchorPos(0) {};
+		pLastTabVTN(NULL), AnchorPos(Indent) {};
 	void AdvanceBy(MILLIPOINT Advance);
 	BOOL FinishTabSection(VisibleTextNode* pLastFormattedNode, BOOL IsLastTabSection);
 	BOOL IsAvailable(MILLIPOINT CharWidth, BOOL IsATab);
@@ -369,18 +369,22 @@
 	MILLIPOINT    GetLineSpacing()     { return mLineSpacing; }
 	FIXED16       GetLineSpaceRatio()  { return mLineSpaceRatio; }
 	MILLIPOINT    GetParaLeftMargin()  { return mLeftMargin; }
+	MILLIPOINT    GetParaFirstIndent() { return mFirstIndent; }
 	MILLIPOINT    GetParaRightMargin() { return mRightMargin; }
 	const TxtRuler* GetRuler()         { return mpRuler; }
 	void SetJustification(  Justification justification) { mJustification  = justification; }
 	void SetLineSpacing(    MILLIPOINT    Spacing)       { mLineSpacing    = Spacing; }
 	void SetLineSpaceRatio( FIXED16       SpaceRatio)    { mLineSpaceRatio = SpaceRatio; }
 	void SetParaLeftMargin( MILLIPOINT    Margin)        { mLeftMargin = Margin; }
+	void SetParaFirstIndent(MILLIPOINT    Indent)        { mFirstIndent = Indent; }
 	void SetParaRightMargin(MILLIPOINT    Margin)        { mRightMargin = Margin; }
 	void SetRuler(          const TxtRuler* pRuler)      { mpRuler = pRuler; }
 
 	MILLIPOINT GetPosInStory() { return mPosInStory; }
 	void SetPosInStory(MILLIPOINT pos) { mPosInStory=pos; }
 
+protected:
+    MILLIPOINT GetEffectiveLeftMargin();
 private:
 	MILLIPOINT mLineDescent;	// largest descent of any char in all fonts on the line
 	MILLIPOINT mLineAscent;		// largest  ascent of any char in all fonts on the line
@@ -390,6 +394,7 @@
 	MILLIPOINT    mLineSpacing;		// cache for value read from attr stack
 	FIXED16       mLineSpaceRatio;	// cache for value read from attr stack
 	MILLIPOINT mLeftMargin;	        // cache for value read from attr stack
+	MILLIPOINT mFirstIndent;        // cache for value read from attr stack
 	MILLIPOINT mRightMargin;        // cache for value read from attr stack
 	const TxtRuler* mpRuler;        // cache for value read from attr stack
 									// NB - this is a shared pointer to a list object owned by the attribute!
Index: Trunk/XaraLX/wxOil/oilruler.cpp
===================================================================
--- Trunk/XaraLX/wxOil/oilruler.cpp	(revision 1471)
+++ Trunk/XaraLX/wxOil/oilruler.cpp	(revision 1472)
@@ -1005,6 +1005,15 @@
 
 	// Convert the click position to OIL coordinates before passing to the kernel.
 	OilCoord ocoord = ClientToOil(pDocView, point);
+	// Only the ordinate in the main ruler direction should be converted, the coordinate
+	// translation does not make any sense in the other direction. Instead, we keep the
+	// window-relative coordinate but we change it in such a way that the paper side of
+	// the ruler is coordinate 0 because the Kernel does not know the RenderWidth of the
+	// ruler and the paper side is the significant side where the blobs are drawn.
+	if (IsHorizontal())
+		ocoord.y = RenderWidth - point.y;
+	else
+		ocoord.x = RenderWidth - point.x;
 	return pKernelRuler->OnRulerClick(ocoord, t, m_LastClickMods);
 }
 


Xara