View Issue Details

IDProjectCategoryView StatusLast Update
0009156ScribusCanvaspublic2012-06-19 19:39
Reporterpspencer Assigned Tocezaryece  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
PlatformlinuxOSFedoraOS Version10
Product Version1.3.7 
Target Version1.5.0Fixed in Version1.5.0svn 
Summary0009156: Feature: adjust frame to contents for text frames
DescriptionThis is one of what will be several feature-request reports I will be filing over the next few weeks, after we tried unsuccessfully to persuade someone to use Scribus so we didn't have to maintain an InDesign installation and she came up with a list of specific shortcomings of Scribus versus InDesign for her work.

In InDesign you can double-click the bottom of a text frame to automatically adjust the frame's height to fit the contents, and can double-click the bottom-right to automatically adjust both the width and the height for "optimal" text flow (using some algorithm I don't entirely understand, but whose most useful purpose is to shrink both the width and the height of a single-line text frame).

This is very useful for typesetting frames with short one-line captions, and for adjusting frame height after altering text content, rather than having to drag to a manually chosen height.

The attached patch implements this. If the bottom frame handle is double-clicked, it adjusts the height to find the smallest height that doesn't cause overflow (but won't go smaller than 10 points or larger than to the bottom of the page). If the bottom-right corner is double-clicked, it first adjusts the height and then tries to shrink the width as much as possible without creating overflow.

For a text frame that links to another frame, where there is already overflow into the other frame, it simply reduces height/width as much as possible without pushing additional characters into the other frame.

I first tried to implement this by seeing how much free space was left over then reducing height by a corresponding amount, but could see no way to make that work with frames of non-rectangular shape or frames with multiple columns where the column breaks might be influenced by other factors. So instead it now just does a straight binary search. The trial resizings are not entered into
the undo mechanism, but after the trial and error process the original dimensions are restored then an undoable change is made to the new size.
Tagsusability
Patch

Activities

pspencer

2010-06-10 20:46

reporter   ~0024036

Arggh, just noticed I after hitting Submit that I submitted a bad patch (forgot the page offset). I'll upload a corrected one in a few minutes.

pspencer

2010-06-10 21:09

reporter  

scribus-1.3.7-textsnap-corrected.patch (3,432 bytes)   
--- Scribus-orig/scribus/canvasmode_normal.cpp	2010-06-07 15:24:19.000000000 -0400
+++ Scribus/scribus/canvasmode_normal.cpp	2010-06-10 14:07:54.000000000 -0400
@@ -212,6 +212,10 @@
 		}
 		else if (currItem->itemType() == PageItem::TextFrame)
 		{
+			// See if double click was on a frame handle
+			FPoint p = m_canvas->globalToCanvas(m->globalPos());
+			Canvas::FrameHandle fh = m_canvas->frameHitTest(QPointF(p.x(),p.y()), currItem);
+
 			//CB old code
 			//emit currItem->isAnnotation() ? AnnotProps() : Amode(modeEdit);
 			//mousePressEvent(m);
@@ -222,6 +226,80 @@
 				m_view->requestMode(submodeAnnotProps);
 				//mousePressEvent(m);
 			}
+
+			//else if on the south or southeast frame handle,
+			//adjust text frame size to fit contents
+			else if (fh == Canvas::SOUTH || fh == Canvas::SOUTHEAST) {
+				currItem->layout();
+				double w = currItem->width();
+				double h = currItem->height();
+				double worig = w;  // Remember original width and height
+				double horig = h;
+				// Bounds of binary search for optimal height:
+				//    hmin = too small (text overflows, or
+				//    	  box would be unreasonably short (< 10pt))
+				//    hmax = big enough (text does not overflow,
+				//        or box is as big as will fit on page)
+				double hmin = 10;
+				double hmax = qMax(10.0, m_doc->Pages->at(currItem->OwnPage)->yOffset() + m_doc->Pages->at(currItem->OwnPage)->height() - currItem->yPos());
+				// Criterion for "text overflows":
+				//   If no linked frame after this one,
+				//     normal meaning of "overflows".
+				//   If linked frame after this one,
+				//     means more characters get shifted
+				//     to that frame than are currently
+				PageItem *next = currItem->nextInChain();
+				int lc = currItem->lastInFrame();
+
+				if (h > hmax) h = hmax;
+				if (h < hmin) h = hmin;
+				while (hmax - hmin > 0.1) {
+				    if (next ? currItem->lastInFrame() < lc : currItem->frameOverflows()) {
+					hmin = h;
+					h = (h+hmax)/2.0;
+				    } else {
+					hmax = h;
+					h = (h+hmin)/2.0;
+				    }
+				    currItem->setWidthHeight(w,h,true);
+				    currItem->invalidateLayout();
+				    currItem->updateClip();
+				    currItem->layout(); 
+				}
+				// hmax is now the height we want.
+				// If on southeast frame point, also
+				// shrink width until text overflows.
+				double wmin = 10;
+				double wmax = w;
+				if (fh == Canvas::SOUTHEAST) {
+				    currItem->setWidthHeight(w,hmax,true);
+				    currItem->invalidateLayout();
+				    currItem->updateClip();
+				    currItem->layout(); 
+				    while (wmax - wmin > 0.1) {
+				        if (next ? currItem->lastInFrame() < lc : currItem->frameOverflows()) {
+					    wmin = w;
+					    w = (w+wmax)/2.0;
+					} else {
+					    wmax = w;
+					    w = (w+wmin)/2.0;
+					}
+					currItem->setWidthHeight(w,hmax,true);
+				        currItem->invalidateLayout();
+				        currItem->updateClip();
+				        currItem->layout(); 
+				    }
+				}
+				// Restore original width, height for undo manager to remember
+				currItem->setWidthHeight(worig,horig,true);
+				// then set new width and height
+				currItem->setWidthHeight(wmax,hmax,false);
+				currItem->invalidateLayout();
+				currItem->updateClip();
+				currItem->layout(); 
+				m_doc->regionsChanged()->update(QRect());
+			} 
+
 			//else if not in mode edit, set mode edit
 			else if (m_doc->appMode != modeEdit)
 			{

StefanM

2012-01-06 09:14

reporter   ~0027473

@pspencer I like that "bottom of a text frame to automatically adjust the frame's height to fit the contents", saves a lot of clicks in newspaper layout.

Reading your patch code: your patch fires only if frame handle is double-clicked.
I feel there should be a key and/or menu entry for this, as double clicking on frames is very messy in scribus.

More general: clicking on specific parts on scribus frames is a major usability problem, as you dont know which frame will be selected on a page with many overlapping frames. A workaround is using layers.

ale

2012-06-18 06:33

manager   ~0028180

i think that cezary is working on this...

cezaryece

2012-06-19 13:59

updater   ~0028217

Last edited: 2012-06-19 14:00

First initial patch for that issue.

For now it only brings two features:
1. adjusting text frame height to last line(s) descents (no matter if text fits in frame or flow away - frame`s height only shrinks to descents in last lines
Action has menu and contextmenu entry and is applicable by double click on bottom frame handle.
2. resize item size to page margin (in direction from which handle is clicked - right handle - resize to right margin, left handle - left margin, bottom/right handle - to bottom/left margin corner). As benefit it is working for all frames (image, render).

Patch is attached, you can see also autoheight branch in our scribus.git repo.

cezaryece

2012-06-19 13:59

updater  

autoheight.diff (21,389 bytes)   
diff --git a/Scribus/scribus/actionmanager.cpp b/Scribus/scribus/actionmanager.cpp
index b0348b1..60c01e1 100644
--- a/Scribus/scribus/actionmanager.cpp
+++ b/Scribus/scribus/actionmanager.cpp
@@ -449,6 +449,8 @@ void ActionManager::initItemMenuActions()
 	scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow));
 	name="tableAdjustFrameToTable";
 	scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow));
+	name="itemAdjustFrameHeightToText";
+	scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow));
 	name = "tableAdjustTableToFrame";
 	scrActions->insert(name, new ScrAction("", defaultKey(name), mainWindow));
 	name="itemAdjustFrameToImage";
@@ -1107,6 +1109,7 @@ void ActionManager::disconnectNewDocActions()
 	disconnect( (*scrActions)["tableDistributeColumnsEvenly"], 0, 0, 0 );
 	disconnect( (*scrActions)["tableAdjustFrameToTable"], 0, 0, 0 );
 	disconnect( (*scrActions)["tableAdjustTableToFrame"], 0, 0, 0 );
+	disconnect( (*scrActions)["itemAdjustFrameHeightToText"], 0, 0, 0 );
 	disconnect( (*scrActions)["itemAdjustFrameToImage"], 0, 0, 0 );
 	disconnect( (*scrActions)["itemAdjustImageToFrame"], 0, 0, 0 );
 	disconnect( (*scrActions)["itemLock"], 0, 0, 0);
@@ -1129,7 +1132,6 @@ void ActionManager::disconnectNewDocActions()
 	disconnect( (*scrActions)["itemRaise"], 0, 0, 0);
 	disconnect( (*scrActions)["toolsUnlinkTextFrameWithTextCopy"], 0, 0, 0 );
 	disconnect( (*scrActions)["toolsUnlinkTextFrameWithTextCut"], 0, 0, 0 );
-
 }
 
 void ActionManager::connectNewDocActions(ScribusDoc *currDoc)
@@ -1159,6 +1161,7 @@ void ActionManager::connectNewDocActions(ScribusDoc *currDoc)
 	connect( (*scrActions)["tableDistributeColumnsEvenly"], SIGNAL(triggered()), currDoc, SLOT(itemSelection_DistributeTableColumnsEvenly()));
 	connect( (*scrActions)["tableAdjustFrameToTable"], SIGNAL(triggered()), currDoc, SLOT(itemSelection_AdjustFrameToTable()));
 	connect( (*scrActions)["tableAdjustTableToFrame"], SIGNAL(triggered()), currDoc, SLOT(itemSelection_AdjustTableToFrame()));
+	connect( (*scrActions)["itemAdjustFrameHeightToText"], SIGNAL(triggered()), currDoc, SLOT(itemSelection_AdjustFrameHeightToText()) );
 	connect( (*scrActions)["itemAdjustFrameToImage"], SIGNAL(triggered()), currDoc, SLOT(itemSelection_AdjustFrametoImageSize()) );
 	connect( (*scrActions)["itemAdjustImageToFrame"], SIGNAL(triggered()), currDoc, SLOT(itemSelection_AdjustImagetoFrameSize()) );
 	connect( (*scrActions)["itemsUnWeld"], SIGNAL(triggered()), currDoc, SLOT(itemSelection_UnWeld()) );
@@ -1464,6 +1467,7 @@ void ActionManager::languageChange()
 	(*scrActions)["tableDistributeColumnsEvenly"]->setTexts(tr("Distribute Columns Evenly"));
 	(*scrActions)["tableAdjustFrameToTable"]->setTexts(tr("Adjust Frame to Table"));
 	(*scrActions)["tableAdjustTableToFrame"]->setTexts(tr("Adjust Table to Frame"));
+	(*scrActions)["itemAdjustFrameHeightToText"]->setTexts( tr("Adjust Frame Height to Text"));
 	(*scrActions)["itemAdjustFrameToImage"]->setTexts( tr("Adjust Frame to Image"));
 	(*scrActions)["itemAdjustImageToFrame"]->setTexts( tr("Adjust Image to Frame"));
 	(*scrActions)["itemToggleInlineImage"]->setTexts( tr("Embed Image"));
@@ -1939,7 +1943,9 @@ void ActionManager::createDefaultMenus()
 		<< "tableDistributeRowsEvenly"
 		<< "tableDistributeColumnsEvenly"
 		<< "tableAdjustFrameToTable"
+		<< "itemAdjustFrameHeightToText"
 		<< "tableAdjustTableToFrame"
+		<< "itemAdjustFrameHeightToText"
 		<< "itemAdjustFrameToImage" 
 		<< "itemAdjustImageToFrame" 
 		<< "itemToggleInlineImage" 
diff --git a/Scribus/scribus/canvasgesture_resize.cpp b/Scribus/scribus/canvasgesture_resize.cpp
index e4780a1..1588d10 100644
--- a/Scribus/scribus/canvasgesture_resize.cpp
+++ b/Scribus/scribus/canvasgesture_resize.cpp
@@ -183,6 +183,12 @@ void ResizeGesture::mouseReleaseEvent(QMouseEvent *m)
 			if (currItem->asImageFrame())
 				currItem->AdjustPictScale();
 		}
+		else if (m->button() == Qt::RightButton)
+		{
+			const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
+			Canvas::FrameHandle fh = m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem);
+			currItem->resizeToMargin(fh);
+		}
 		m_view->resetMousePressed();
 		// necessary since mousebutton is still recorded pressed, and otherwise checkchanges() will do nothing
 		// we must check changes on whole selection otherwise resize operation won't undo correctly on groups
diff --git a/Scribus/scribus/canvasmode_normal.cpp b/Scribus/scribus/canvasmode_normal.cpp
index 3007ba5..ee0ce5c 100644
--- a/Scribus/scribus/canvasmode_normal.cpp
+++ b/Scribus/scribus/canvasmode_normal.cpp
@@ -223,6 +223,9 @@ void CanvasMode_Normal::mouseDoubleClickEvent(QMouseEvent *m)
 		}
 		else if (currItem->itemType() == PageItem::TextFrame)
 		{
+			// See if double click was on a frame handle
+			FPoint p = m_canvas->globalToCanvas(m->globalPos());
+			Canvas::FrameHandle fh = m_canvas->frameHitTest(QPointF(p.x(),p.y()), currItem);
 			//CB old code
 			//emit currItem->isAnnotation() ? AnnotProps() : Amode(modeEdit);
 			//mousePressEvent(m);
@@ -233,6 +236,8 @@ void CanvasMode_Normal::mouseDoubleClickEvent(QMouseEvent *m)
 				m_view->requestMode(submodeAnnotProps);
 				//mousePressEvent(m);
 			}
+			else if (fh == Canvas::SOUTH)
+				currItem->asTextFrame()->setTextFrameHeight();
 			//else if not in mode edit, set mode edit
 			else if (m_doc->appMode != modeEdit)
 			{
diff --git a/Scribus/scribus/pageitem.cpp b/Scribus/scribus/pageitem.cpp
index edf0a74..05ede18 100644
--- a/Scribus/scribus/pageitem.cpp
+++ b/Scribus/scribus/pageitem.cpp
@@ -7470,3 +7470,52 @@ void PageItem::unWeld()
 	}
 	weldList.clear();
 }
+
+
+void PageItem::resizeToMargin(Canvas::FrameHandle direction)
+{
+	//FIX ME: for now avoid for rotated items
+	if (rotation() != 0)
+		return;
+	ScPage *currPage = m_Doc->Pages->at(OwnPage);
+	QMatrix ma;
+	ma.translate(xPos(), yPos());
+	double inX = ma.dx() - m_Doc->rulerXoffset;
+	double inY = ma.dy() - m_Doc->rulerYoffset;
+	if (m_Doc->guidesPrefs().rulerMode)
+	{
+		inX -= m_Doc->currentPage()->xOffset();
+		inY -= m_Doc->currentPage()->yOffset();
+	}
+	if (direction == Canvas::NORTH || direction == Canvas::NORTHWEST || direction == Canvas::NORTHEAST)
+	{
+		double top = currPage->topMargin();
+		double dY = inY - top;
+		moveBy(0, -dY);
+		setHeight(height() + dY);
+	}
+	if (direction == Canvas::SOUTH || direction == Canvas::SOUTHWEST || direction == Canvas::SOUTHEAST)
+	{
+		double bottom = currPage->height() - currPage->bottomMargin();
+		double dY = bottom - (inY + height());
+		setHeight(height() + dY);
+	}
+	if (direction == Canvas::EAST || direction == Canvas::NORTHEAST || direction == Canvas::SOUTHEAST)
+	{
+		double right = currPage->width() - currPage->rightMargin();
+		double dX = right - (inX + width());
+		setWidth(width() + dX);
+	}
+	if (direction == Canvas::WEST || direction == Canvas::NORTHWEST || direction == Canvas::SOUTHWEST)
+	{
+		double left = currPage->leftMargin();
+		double dX = inX - left;
+		moveBy(-dX,0);
+		setWidth(width() + dX);
+	}
+
+	updateClip();
+	invalid = true;
+	m_Doc->changed();
+	m_Doc->regionsChanged()->update(QRect());
+}
diff --git a/Scribus/scribus/pageitem.h b/Scribus/scribus/pageitem.h
index 19b877f..7a71637 100644
--- a/Scribus/scribus/pageitem.h
+++ b/Scribus/scribus/pageitem.h
@@ -38,6 +38,7 @@ for which a new license (GPL+exception) is in place.
 
 #include "scribusapi.h"
 #include "annotation.h"
+#include "canvas.h"
 #include "colormgmt/sccolormgmtstructs.h"
 #include "desaxe/saxio.h"
 #include "observable.h"
@@ -1574,8 +1575,11 @@ signals:
 	//void textToFrameDistances(double, double, double, double); //left, top, bottom, right: Extra, TExtra, BExtra, RExtra
 	//FIXME: columns, grid ?
 	
-	//items welding (item follows while item moves which they are connected with)
 public:
+	//resize item to margin in direction given from clicked handle
+	void resizeToMargin(Canvas::FrameHandle direction);
+
+	//items welding (item follows while item moves which they are connected with)
 	struct weldingInfo
 	{
 		PageItem *weldItem;
diff --git a/Scribus/scribus/pageitem_textframe.cpp b/Scribus/scribus/pageitem_textframe.cpp
index 23ad9c1..de8d15a 100644
--- a/Scribus/scribus/pageitem_textframe.cpp
+++ b/Scribus/scribus/pageitem_textframe.cpp
@@ -1427,6 +1427,7 @@ void PageItem_TextFrame::layout()
 		current.mustLineEnd = current.colRight;
 		current.restartX = 0;
 		int lastStat = 0, curStat = 0;
+		setMaxY(-1);
 
 		for (int a = firstInFrame(); a < itemText.length(); ++a)
 		{
@@ -1823,7 +1824,7 @@ void PageItem_TextFrame::layout()
 				}
 			}
 			current.recalculateY = true;
-			int maxYAsc = 0, maxYDesc = 0;
+			double maxYAsc = 0.0, maxYDesc = 0.0;
 			if (current.startOfCol)
 			{
 				//qMax is used for glyphs shifted or vertically scalled above ascent or below descent
@@ -1835,13 +1836,13 @@ void PageItem_TextFrame::layout()
 					else if (firstLineOffset() == FLOPLineSpacing)
 						addAsce = style.lineSpacing();
 				}
-				maxYAsc = static_cast<int>(floor(current.yPos - addAsce));
+				maxYAsc = current.yPos - addAsce;
 			}
 			else
-				maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce)));
+				maxYAsc = current.yPos - qMax(realAsce, asce);
 			//fix for glyphs with negative realAsce value
-			maxYAsc = qMax(maxYAsc, 0);
-			maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc)));
+			maxYAsc = qMax(maxYAsc, 0.0);
+			maxYDesc = current.yPos + qMax(realDesc, desc);
 
 			if (current.itemsInLine == 0 && !current.afterOverflow)
 			{
@@ -1849,8 +1850,8 @@ void PageItem_TextFrame::layout()
 				goNoRoom = false;
 
 				// find line`s start
-				pt1 = QPoint(static_cast<int>(floor(current.xPos)), maxYAsc);
-				pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))),maxYDesc);
+				pt1 = QPoint(static_cast<int>(floor(current.xPos)), static_cast<int>(floor(maxYAsc)));
+				pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))), static_cast<int>(ceil(maxYDesc)));
 				pt = QRect(pt1, pt2);
 				realEnd = 0;
 				//check if there is overflow at start of line, if so jump behind it and check again
@@ -1877,7 +1878,7 @@ void PageItem_TextFrame::layout()
 					//check if in indent any overflow occurs
 					while (Xpos <= Xend && Xpos < current.colRight)
 					{
-						pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)),maxYAsc));
+						pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)), static_cast<int>(floor(maxYAsc))));
 						if (!regionContainsRect(m_availableRegion, pt))
 						{
 							Xpos = current.xPos = realEnd = findRealOverflowEnd(m_availableRegion, pt, current.colRight);
@@ -1909,7 +1910,7 @@ void PageItem_TextFrame::layout()
 							current.yPos += (current.startOfCol ? 1 : style.lineSpacing());
 						else
 							current.yPos++;
-						lastLineY = maxYAsc +1;
+						lastLineY = maxYAsc;
 						if (current.startOfCol)
 						{
 							//qMax is used for glyphs shifted or vertically scalled above ascent or below descent
@@ -1921,13 +1922,13 @@ void PageItem_TextFrame::layout()
 								else if (firstLineOffset() == FLOPLineSpacing)
 									addAsce = style.lineSpacing();
 							}
-							maxYAsc = static_cast<int>(floor(current.yPos - addAsce));
+							maxYAsc = current.yPos - addAsce;
 						}
 						else
-							maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce)));
-						maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc)));
+							maxYAsc = current.yPos - qMax(realAsce, asce);
+						maxYDesc = current.yPos + qMax(realDesc, desc);
 
-						pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)),maxYAsc));
+						pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)), static_cast<int>(floor(maxYAsc))));
 						done = false;
 					}
 					if (current.isEndOfCol(realDesc))
@@ -2220,24 +2221,24 @@ void PageItem_TextFrame::layout()
 				{
 					if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN)
 					{
-						pt1 = QPoint(charStart, maxYAsc);
-						pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), maxYDesc);
+						pt1 = QPoint(charStart,  static_cast<int>(floor(maxYAsc)));
+						pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), static_cast<int>(ceil(maxYDesc)));
 					}
 					else
 					{
-						pt1 = QPoint(charStart, maxYAsc);
-						pt2 = QPoint(charEnd, maxYDesc);
+						pt1 = QPoint(charStart, static_cast<int>(floor(maxYAsc)));
+						pt2 = QPoint(charEnd, static_cast<int>(ceil(maxYDesc)));
 					}
 				}
 				else if (!legacy && SpecialChars::isBreakingSpace(hl->ch))
 				{
-					pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), maxYAsc);
-					pt2 = QPoint(charEnd, maxYDesc);
+					pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), static_cast<int>(floor(maxYAsc)));
+					pt2 = QPoint(charEnd, static_cast<int>(ceil(maxYDesc)));
 				}
 				else
 				{
-					pt1 = QPoint(charStart, maxYAsc);
-					pt2 = QPoint(charEnd, maxYDesc);
+					pt1 = QPoint(charStart, static_cast<int>(floor(maxYAsc)));
+					pt2 = QPoint(charEnd, static_cast<int>(ceil(maxYDesc)));
 				}
 				pt = QRect(pt1, pt2);
 				if (!regionContainsRect(m_availableRegion, pt))
@@ -2323,6 +2324,8 @@ void PageItem_TextFrame::layout()
 					else
 						inOverflow = true;
 				}
+				else
+					setMaxY(maxYDesc);
 			}
 
 			// hyphenation
@@ -2399,7 +2402,7 @@ void PageItem_TextFrame::layout()
 				{
 					// find end of line
 					current.breakLine(itemText, style, firstLineOffset(), a);
-					EndX = current.endOfLine(m_availableRegion, style.rightMargin(), maxYAsc, maxYDesc);
+					EndX = current.endOfLine(m_availableRegion, style.rightMargin(), static_cast<int>(floor(maxYAsc)), static_cast<int>(ceil(maxYDesc)));
 					current.finishLine(EndX);
 					//addLine = true;
 					assert(current.addLine);
@@ -2476,7 +2479,7 @@ void PageItem_TextFrame::layout()
 						current.updateHeightMetrics(itemText);
 						//current.updateLineOffset(itemText, style, firstLineOffset());
 						//current.xPos = current.breakXPos;
-						EndX = current.endOfLine(m_availableRegion, current.rightMargin, maxYAsc, maxYDesc);
+						EndX = current.endOfLine(m_availableRegion, current.rightMargin, static_cast<int>(floor(maxYAsc)), static_cast<int>(ceil(maxYDesc)));
 						current.finishLine(EndX);
 						
 						hyphWidth = 0.0;
@@ -2549,7 +2552,11 @@ void PageItem_TextFrame::layout()
 						}
 						goNextColumn = true;
 					}
+					else
+						setMaxY(maxYDesc);
 				}
+				else
+					setMaxY(maxYDesc);
 				if (current.line.firstItem <= current.line.lastItem && current.itemsInLine > 0)
 				{
 					if (current.addLine && current.breakIndex >= 0)
@@ -2563,6 +2570,7 @@ void PageItem_TextFrame::layout()
 						fillInTabLeaders(itemText, current.line);
 						//if right margin is set we temporally save line, not append it
 						itemText.appendLine(current.line);
+						setMaxY(maxYDesc);
 						current.restartIndex = current.line.lastItem +1;
 						a = current.restartIndex -1;
 						current.rowDesc = qMax(current.rowDesc,current.yPos + current.line.descent);
@@ -2606,7 +2614,6 @@ void PageItem_TextFrame::layout()
 							maxDX = 0;
 						}
 					}
-					lastLineY = current.rowDesc;
 					current.mustLineEnd = current.colRight;
 					current.restartRowIndex = current.restartIndex;
 				}
@@ -2749,6 +2756,7 @@ void PageItem_TextFrame::layout()
 			goNextColumn = false;
 
 			itemText.appendLine(current.line);
+			setMaxY(maxYDesc);
 			current.startOfCol = false;
 
 			if (moveLinesFromPreviousFrame ()) {
@@ -4202,7 +4210,10 @@ void PageItem_TextFrame::applicableActions(QStringList & actionList)
 	}
 	actionList << "itemConvertToOutlines";
 	if (itemText.lines() != 0)
+	{
 		actionList << "editClearContents";
+		actionList << "itemAdjustFrameHeightToText";
+	}
 }
 
 QString PageItem_TextFrame::infoDescription()
@@ -4214,3 +4225,20 @@ void PageItem_TextFrame::slotInvalidateLayout()
 {
 	invalidateLayout();
 }
+
+void PageItem_TextFrame::setMaxY(double y)
+{
+	if (y == -1)
+		maxY = 0;
+	else
+		maxY = qMax(y, maxY);
+}
+
+void PageItem_TextFrame::setTextFrameHeight()
+{
+	setHeight(ceil(maxY) + BExtra + 0.5);
+	updateClip();
+	invalid = true;
+	m_Doc->changed();
+	m_Doc->regionsChanged()->update(QRect());
+}
diff --git a/Scribus/scribus/pageitem_textframe.h b/Scribus/scribus/pageitem_textframe.h
index d178410..50bd63d 100644
--- a/Scribus/scribus/pageitem_textframe.h
+++ b/Scribus/scribus/pageitem_textframe.h
@@ -116,6 +116,13 @@ private:
 	QMap<QString,StoryText> shadows;
 	bool checkKeyIsShortcut(QKeyEvent *k);
 	
+	// set text frame height to last line of text
+	double maxY;
+	void setMaxY(double y);
+
+public:
+	void setTextFrameHeight();
+
 private slots:
 	void slotInvalidateLayout();
 };
diff --git a/Scribus/scribus/scribus.cpp b/Scribus/scribus/scribus.cpp
index 7058096..a44a2ac 100644
--- a/Scribus/scribus/scribus.cpp
+++ b/Scribus/scribus/scribus.cpp
@@ -799,6 +799,7 @@ void ScribusMainWindow::initMenuBar()
 	scrMenuMgr->addMenuSeparator("Item");
 	// End Table submenu.
 	scrMenuMgr->addMenuSeparator("Item");
+	scrMenuMgr->addMenuItem(scrActions["itemAdjustFrameHeightToText"], "Item", false);
 	scrMenuMgr->addMenuItem(scrActions["itemAdjustFrameToImage"], "Item", false);
 	scrMenuMgr->addMenuItem(scrActions["itemAdjustImageToFrame"], "Item", false);
 	scrMenuMgr->addMenuItem(scrActions["itemUpdateImage"], "Item", false);
@@ -2644,6 +2645,7 @@ void ScribusMainWindow::HaveNewSel(int SelectedType)
 #else
 	scrActions["editEditRenderSource"]->setEnabled(SelectedType==PageItem::ImageFrame && currItem && (currItem->asLatexFrame()));
 #endif
+	scrActions["itemAdjustFrameHeightToText"]->setEnabled(SelectedType==PageItem::TextFrame && currItem->itemText.length() >0);
 	if (SelectedType!=PageItem::ImageFrame)
 	{
 		scrActions["itemImageIsVisible"]->setChecked(false);
diff --git a/Scribus/scribus/scribusdoc.cpp b/Scribus/scribus/scribusdoc.cpp
index 282e200..d6869d4 100644
--- a/Scribus/scribus/scribusdoc.cpp
+++ b/Scribus/scribus/scribusdoc.cpp
@@ -14389,6 +14389,31 @@ void ScribusDoc::itemSelection_AdjustImagetoFrameSize( Selection *customSelectio
 	}
 }
 
+void ScribusDoc::itemSelection_AdjustFrameHeightToText( Selection *customSelection)
+{
+	Selection* itemSelection = (customSelection!=0) ? customSelection : m_Selection;
+	assert(itemSelection!=0);
+	uint selectedItemCount=itemSelection->count();
+	if (selectedItemCount == 0)
+		return;
+	
+	if (selectedItemCount > 0)
+	{
+		for (uint i = 0; i < selectedItemCount; ++i)
+		{
+			PageItem *currItem = itemSelection->itemAt(i);
+			if (currItem!=NULL)
+			{
+				if (currItem->asTextFrame() && (currItem->itemText.length() > 0) && !currItem->isTableItem)
+					currItem ->asTextFrame()->setTextFrameHeight();
+			}
+		}
+		regionsChanged()->update(QRectF());
+		changed();
+		itemSelection->itemAt(0)->emitAllToGUI();
+	}
+}
+
 void ScribusDoc::itemSelection_AdjustFrameToTable()
 {
 	// TODO: Do this in an undo transaction?
diff --git a/Scribus/scribus/scribusdoc.h b/Scribus/scribus/scribusdoc.h
index ad46b78..34b2aba 100644
--- a/Scribus/scribus/scribusdoc.h
+++ b/Scribus/scribus/scribusdoc.h
@@ -1452,6 +1452,7 @@ public slots:
 	 * Adjust an image size to fit the size of the frame
 	 */
 	void itemSelection_AdjustImagetoFrameSize(Selection* customSelection=0);
+	void itemSelection_AdjustFrameHeightToText( Selection *customSelection=0);
 	//! @brief startArrowID or endArrowID of -1 mean not applying a selection at this point.
 	void itemSelection_ApplyArrowHead(int startArrowID=-1, int endArrowID=-1, Selection* customSelection=0);
 	void itemSelection_ApplyArrowScale(int startArrowSc, int endArrowSc, Selection* customSelection);
diff --git a/Scribus/scribus/ui/contextmenu.cpp b/Scribus/scribus/ui/contextmenu.cpp
index 3edd30c..5906998 100644
--- a/Scribus/scribus/ui/contextmenu.cpp
+++ b/Scribus/scribus/ui/contextmenu.cpp
@@ -216,7 +216,8 @@ void ContextMenu::createMenuItems_Selection()
 			addAction(m_AP->scrActions["tableAdjustFrameToTable"]);
 		if (m_actionList.contains("tableAdjustTableToFrame"))
 			addAction(m_AP->scrActions["tableAdjustTableToFrame"]);
-
+		if (m_actionList.contains("itemAdjustFrameHeightToText"))
+			addAction(m_AP->scrActions["itemAdjustFrameHeightToText"]);
 		if (m_actionList.contains("itemExtendedImageProperties"))
 			addAction(m_AP->scrActions["itemExtendedImageProperties"]);
 		if (m_actionList.contains("itemAdjustFrameToImage"))
@@ -270,6 +271,11 @@ void ContextMenu::createMenuItems_Selection()
 			}
 		}
 		
+		if ((selectedItemCount==1) && currItem->asTextFrame())
+		{
+			if (currItem->itemText.length() > 0)
+				m_AP->scrActions["itemAdjustFrameHeightToText"]->setEnabled(true);
+		}
 	}
 	//-->
 	
autoheight.diff (21,389 bytes)   

cbradney

2012-06-19 19:27

administrator   ~0028223

First part committed.. I'd prefer other options for activating 2) and it to be in scribusdoc probably rather than pageitem.

Issue History

Date Modified Username Field Change
2010-06-10 20:41 pspencer New Issue
2010-06-10 20:41 pspencer File Added: scribus-1.3.7-textsnap.patch
2010-06-10 20:46 pspencer Note Added: 0024036
2010-06-10 21:09 pspencer File Added: scribus-1.3.7-textsnap-corrected.patch
2010-06-11 21:27 jghali File Deleted: scribus-1.3.7-textsnap.patch
2010-06-11 21:29 jghali Target Version => 1.5.0
2012-01-06 08:49 StefanM Tag Attached: usability
2012-01-06 09:14 StefanM Note Added: 0027473
2012-06-18 06:33 ale Note Added: 0028180
2012-06-18 19:25 ale Assigned To => cezaryece
2012-06-18 19:25 ale Status new => assigned
2012-06-19 13:59 cezaryece Note Added: 0028217
2012-06-19 13:59 cezaryece File Added: autoheight.diff
2012-06-19 14:00 cezaryece Note Edited: 0028217
2012-06-19 19:27 cbradney Note Added: 0028223
2012-06-19 19:33 cbradney Status assigned => resolved
2012-06-19 19:33 cbradney Fixed in Version => 1.5.0svn
2012-06-19 19:33 cbradney Resolution open => fixed
2012-06-19 19:39 cbradney Status resolved => closed