void LayoutLabel() { if (FontAtlas == null || string.IsNullOrEmpty(Text)) { ContentSize = CCSize.Zero; return; } TextureAtlas.RemoveAllQuads(); Descendants.Clear(); lettersInfo.Clear(); FontAtlas.PrepareLetterDefinitions(Text); var start = 0; var typesetter = new CCTLTextLayout(this); var length = Text.Length; var insetBounds = labelDimensions; var layoutAvailable = true; if (insetBounds == CCSize.Zero) { insetBounds = new CCSize(8388608, 8388608); layoutAvailable = false; } var boundsWidth = insetBounds.Width; var contentScaleFactorWidth = CCLabel.DefaultTexelToContentSizeRatios.Width; var contentScaleFactorHeight = CCLabel.DefaultTexelToContentSizeRatios.Height; List <CCTLLine> lineList = new List <CCTLLine>(); while (start < length)// && textPosition.Y < insetBounds.Bottom) { // Now we ask the typesetter to break off a line for us. // This also will take into account line feeds embedded in the text. // Example: "This is text \n with a line feed embedded inside it" int count = typesetter.SuggestLineBreak(start, boundsWidth); var line = typesetter.GetLine(start, start + count); lineList.Add(line); start += count; } // Calculate our vertical starting position var totalHeight = lineList.Count * LineHeight; var nextFontPositionY = totalHeight; if (Dimensions.Height > 0) { var labelHeightPixel = Dimensions.Height * contentScaleFactorHeight; if (totalHeight > labelHeightPixel) { int numLines = (int)(labelHeightPixel / LineHeight); totalHeight = numLines * LineHeight; } switch (VerticalAlignment) { case CCVerticalTextAlignment.Top: nextFontPositionY = labelHeightPixel; break; case CCVerticalTextAlignment.Center: nextFontPositionY = (labelHeightPixel + totalHeight) * 0.5f; break; case CCVerticalTextAlignment.Bottom: nextFontPositionY = totalHeight; break; default: break; } } var lineGlyphIndex = 0; float longestLine = (labelDimensions.Width > 0) ? labelDimensions.Width : 0; // Used for calculating overlapping on last line character var lastCharWidth = 0.0f; int lastCharAdvance = 0; // Define our horizontal justification var flushFactor = (float)HorizontalAlignment / (float)CCTextAlignment.Right; // We now loop through all of our line's glyph runs foreach (var line in lineList) { var gliphRun = line.GlyphRun; var lineWidth = line.Bounds.Width * contentScaleFactorWidth; var flush = line.PenOffsetForFlush(flushFactor, boundsWidth); foreach (var glyph in gliphRun) { var letterPosition = glyph.Position; var letterDef = glyph.Definition; lastCharWidth = letterDef.Width * contentScaleFactorWidth; letterPosition.X += flush; letterPosition.Y = (nextFontPositionY - letterDef.YOffset) / contentScaleFactorHeight; //recordLetterInfo(letterPosition, glyph.def, lineGlyphIndex++); var tmpInfo = new LetterInfo(); tmpInfo.Definition = letterDef; tmpInfo.Position = letterPosition; tmpInfo.ContentSize.Width = letterDef.Width; tmpInfo.ContentSize.Height = letterDef.Height; if (lineGlyphIndex >= lettersInfo.Count) { lettersInfo.Add(tmpInfo); } else { lettersInfo[lineGlyphIndex] = tmpInfo; } lineGlyphIndex++; lastCharAdvance = (int)glyph.Definition.XAdvance; } // calculate our longest line which is used for calculating our ContentSize if (lineWidth > longestLine) { longestLine = lineWidth; } nextFontPositionY -= LineHeight; } CCSize tmpSize; // If the last character processed has an xAdvance which is less that the width of the characters image, then we need // to adjust the width of the string to take this into account, or the character will overlap the end of the bounding // box if (lastCharAdvance < lastCharWidth) { tmpSize.Width = longestLine - lastCharAdvance + lastCharWidth; } else { tmpSize.Width = longestLine; } tmpSize.Height = totalHeight; if (Dimensions.Height > 0) { tmpSize.Height = Dimensions.Height * contentScaleFactorHeight; } ContentSize = tmpSize / CCLabel.DefaultTexelToContentSizeRatios; lineList.Clear(); CCRect uvRect; CCSprite letterSprite; for (int c = 0; c < Children.Count; c++) { letterSprite = (CCSprite)Children[c]; int tag = letterSprite.Tag; if (tag >= length) { RemoveChild(letterSprite, true); } else if (tag >= 0) { if (letterSprite != null) { uvRect = lettersInfo[tag].Definition.Subrect; letterSprite.TextureRectInPixels = uvRect; letterSprite.ContentSize = uvRect.Size; } } } UpdateQuads(); UpdateColor(); }
void LayoutLabel () { if (FontAtlas == null || string.IsNullOrEmpty(Text)) { ContentSize = CCSize.Zero; return; } TextureAtlas.RemoveAllQuads(); Descendants.Clear(); lettersInfo.Clear(); FontAtlas.PrepareLetterDefinitions(Text); var start = 0; var typesetter = new CCTLTextLayout(this); var length = Text.Length; var insetBounds = labelDimensions; var layoutAvailable = true; if (insetBounds.Width <= 0) { insetBounds.Width = MAX_BOUNDS; layoutAvailable = false; } if (insetBounds.Height <= 0) { insetBounds.Height = MAX_BOUNDS; layoutAvailable = false; } var contentScaleFactorWidth = CCLabel.DefaultTexelToContentSizeRatios.Width; var contentScaleFactorHeight = CCLabel.DefaultTexelToContentSizeRatios.Height; var scaleX = ScaleX; var scaleY = ScaleY; List<CCTLLine> lineList = new List<CCTLLine>(); var boundingSize = CCSize.Zero; while (start < length) { // Now we ask the typesetter to break off a line for us. // This also will take into account line feeds embedded in the text. // Example: "This is text \n with a line feed embedded inside it" int count = typesetter.SuggestLineBreak(start, insetBounds.Width); var line = typesetter.GetLine(start, start + count); lineList.Add(line); if (line.Bounds.Width > boundingSize.Width) boundingSize.Width = line.Bounds.Width; boundingSize.Height += line.Bounds.Height; start += count; } if (!layoutAvailable) { if (insetBounds.Width == MAX_BOUNDS) { insetBounds.Width = boundingSize.Width; } if (insetBounds.Height == MAX_BOUNDS) { insetBounds.Height = boundingSize.Height; } } // Calculate our vertical starting position var totalHeight = lineList.Count * LineHeight; var nextFontPositionY = totalHeight; if (layoutAvailable && labelDimensions.Height > 0) { var labelHeightPixel = labelDimensions.Height / scaleY * contentScaleFactorHeight; if (totalHeight > labelHeightPixel) { int numLines = (int)(labelHeightPixel / LineHeight); totalHeight = numLines * LineHeight; } switch (VerticalAlignment) { case CCVerticalTextAlignment.Top: nextFontPositionY = labelHeightPixel; break; case CCVerticalTextAlignment.Center: nextFontPositionY = (labelHeightPixel + totalHeight) * 0.5f; break; case CCVerticalTextAlignment.Bottom: nextFontPositionY = totalHeight; break; default: break; } } var lineGlyphIndex = 0; float longestLine = 0; // Used for calculating overlapping on last line character var lastCharWidth = 0.0f; int lastCharAdvance = 0; // Define our horizontal justification var flushFactor = (float)HorizontalAlignment / (float)CCTextAlignment.Right; // We now loop through all of our line's glyph runs foreach (var line in lineList) { var gliphRun = line.GlyphRun; var lineWidth = line.Bounds.Width * contentScaleFactorWidth; var flushWidth = (layoutAvailable) ? insetBounds.Width / scaleX : boundingSize.Width; var flush = line.PenOffsetForFlush(flushFactor, flushWidth) ; foreach (var glyph in gliphRun) { var letterPosition = glyph.Position; var letterDef = glyph.Definition; lastCharWidth = letterDef.Width * contentScaleFactorWidth; letterPosition.X += flush; letterPosition.Y = (nextFontPositionY - letterDef.YOffset) / contentScaleFactorHeight; var tmpInfo = new LetterInfo(); tmpInfo.Definition = letterDef; tmpInfo.Position = letterPosition; tmpInfo.ContentSize.Width = letterDef.Width; tmpInfo.ContentSize.Height = letterDef.Height; if (lineGlyphIndex >= lettersInfo.Count) { lettersInfo.Add(tmpInfo); } else { lettersInfo[lineGlyphIndex] = tmpInfo; } lineGlyphIndex++; lastCharAdvance = (int)glyph.Definition.XAdvance; } // calculate our longest line which is used for calculating our ContentSize if (lineWidth > longestLine) longestLine = lineWidth; nextFontPositionY -= LineHeight; } CCSize tmpSize; // If the last character processed has an xAdvance which is less that the width of the characters image, then we need // to adjust the width of the string to take this into account, or the character will overlap the end of the bounding // box if(lastCharAdvance < lastCharWidth) { tmpSize.Width = longestLine - lastCharAdvance + lastCharWidth; } else { tmpSize.Width = longestLine; } tmpSize.Height = totalHeight; if (labelDimensions.Height > 0) { tmpSize.Height = labelDimensions.Height * contentScaleFactorHeight; } // We use base here so we do not trigger an update internally. base.ContentSize = tmpSize / CCLabel.DefaultTexelToContentSizeRatios; lineList.Clear(); CCRect uvRect; CCSprite letterSprite; for (int c = 0; c < Children.Count; c++) { letterSprite = (CCSprite)Children[c]; int tag = letterSprite.Tag; if(tag >= length) { RemoveChild(letterSprite, true); } else if(tag >= 0) { if (letterSprite != null) { uvRect = lettersInfo[tag].Definition.Subrect; letterSprite.TextureRectInPixels = uvRect; letterSprite.ContentSize = uvRect.Size; } } } UpdateQuads(); UpdateColor(); }