public ISpanned CreateStyledString(TextStyleParameters style, string text, int startIndex = 0, int endIndex = -1) { if (text.Length == 0) { return(null); } if (endIndex == -1) { endIndex = text.Length; } if (startIndex >= endIndex) { throw new Exception("Unable to create styled string, StartIndex is too high: " + startIndex); } // Parse the text text = ParseString(style, text); // If we have HMTL if (!string.IsNullOrEmpty(text) && Common.MatchHtmlTags.IsMatch(text)) { return(CreateHtmlString(text, style.Name)); } else { var builder = new SpannableStringBuilder(text); var font = GetFont(style.Font); var span = new CustomTypefaceSpan("", font, style); builder.SetSpan(span, startIndex, endIndex, SpanTypes.ExclusiveExclusive); return(builder); } }
static void UpdateMargins(TextStyleParameters style, ref UIEdgeInsets inset) { inset.Top = (style.PaddingTop > float.MinValue) ? style.PaddingTop : inset.Top; inset.Bottom = (style.PaddingBottom > float.MinValue) ? style.PaddingBottom : inset.Bottom; inset.Left = (style.PaddingLeft > float.MinValue) ? style.PaddingLeft : inset.Left; inset.Right = (style.PaddingRight > float.MinValue) ? style.PaddingRight : inset.Right; }
internal static string ParseString(TextStyleParameters style, string text) { // Text transformations if (!string.IsNullOrEmpty(text)) { if (style.TextTransform != CssTextTransform.None) { switch (style.TextTransform) { case CssTextTransform.UpperCase: text = text.ToUpper(); break; case CssTextTransform.LowerCase: text = text.ToLower(); break; case CssTextTransform.Capitalize: text = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text.ToLower()); break; } } } return(text); }
/// <summary> /// Handles a custom tag /// </summary> /// <returns>void</returns> /// <param name="opening">bool</param> /// <param name="tag">string</param> /// <param name="output">IEditable</param> /// <param name="xmlReader">IXMLReader</param> public void HandleTag(bool opening, string tag, IEditable output, Org.Xml.Sax.IXMLReader xmlReader) { TextStyleParameters style = _styles.ContainsKey(tag) ? _styles [tag] : null; // Body overwrites the inline styles so we set that at the textview level if (style != null) { var text = output as SpannableStringBuilder; if (opening) { Start(text, new TextStylesObject()); } else { // Retrieve font Typeface font = null; if (!string.IsNullOrEmpty(style.Font)) { _instance._typeFaces.TryGetValue(style.Font, out font); } var customSpan = new CustomTypefaceSpan("", font, style); End(style, text, Class.FromType(typeof(TextStylesObject)), customSpan); } } }
/// <summary> /// Sets the style. /// </summary> /// <param name="id">Identifier.</param> /// <param name="style">Style.</param> /// <param name="refresh">If set to <c>true</c> refresh.</param> public virtual void SetStyle(string id, TextStyleParameters style, bool refresh = false) { _textStyles[id] = style; if (refresh) { Refresh(); } }
/// <summary> /// Merge the specified style with this instance and optionally ovwerite any conflicting parameters /// </summary> /// <param name="style">Source.</param> /// <param name="overwriteExisting">Overwrite existing.</param> public void Merge(TextStyleParameters style, bool overwriteExisting) { Type t = typeof(TextStyleParameters); var properties = t.GetRuntimeProperties().Where(prop => prop.CanRead && prop.CanWrite); foreach (var prop in properties) { var sourceValue = prop.GetValue(style, null); if (sourceValue != null) { var targetValue = prop.GetValue(this, null); switch (prop.Name) { case "TextAlign": if ((CssAlign)sourceValue != CssAlign.Left) { targetValue = null; } break; case "TextDecoration": if ((CssDecoration)sourceValue != CssDecoration.None) { targetValue = null; } break; case "TextOverflow": if ((CssTextOverflow)sourceValue != CssTextOverflow.None) { targetValue = null; } break; case "TextTransform": if ((CssTextTransform)sourceValue != CssTextTransform.None) { targetValue = null; } break; } if (targetValue != null && !overwriteExisting) { continue; } prop.SetValue(this, sourceValue, null); } } }
internal NSAttributedString ParseHtmlString(TextStyleParameters style, string text) { var attribs = GetStringAttributes(style, DefaultTextSize); text = ParseString(style, text); var prettyString = new NSMutableAttributedString(text); prettyString.AddAttributes(attribs, new NSRange(0, text.Length)); return(prettyString); }
public void SetDirty(bool forceUpdate) { _isDirty = true; _style = null; _attributedValue = null; if (forceUpdate) { UpdateDisplay(); } }
/// <summary> /// Transforms the text case within the given range. /// </summary> /// <returns>The text range.</returns> /// <param name="text">Text.</param> /// <param name="style">Style.</param> /// <param name="startIndex">Start index.</param> /// <param name="endIndex">End index.</param> void TransformTextRange(SpannableStringBuilder text, TextStyleParameters style, int startIndex, int endIndex) { if (startIndex == endIndex) { return; } var transformed = TextStyle.ParseString(style, text.SubSequence(startIndex, endIndex)); text.Replace(startIndex, endIndex, transformed); }
/// <summary> /// Initializes a new instance of the <see cref="T:TextStyles.Android.CustomHtmlParser"/> class. /// </summary> /// <param name="source">Source.</param> /// <param name="textStyles">Text styles.</param> /// <param name="defaultStyleID">Default style identifier.</param> public CustomHtmlParser(TextStyle instance, string source, Dictionary <string, TextStyleParameters> textStyles, string defaultStyleID = null) { _instance = instance; _htmlSource = source; _styles = textStyles; if (!String.IsNullOrEmpty(defaultStyleID) && _styles.ContainsKey(defaultStyleID)) { _defaultStyle = _styles [defaultStyleID]; } _spannableStringBuilder = new SpannableStringBuilder(); _reader = XMLReaderFactory.CreateXMLReader("org.ccil.cowan.tagsoup.Parser"); _imageGetter = null; _tagHandler = new CustomTagHandler(_instance, _styles); }
/// <summary> /// Creates a styled string as an NSAttibutedString /// </summary> /// <returns>The styled string.</returns> /// <param name="style">TextStyleParameters for styling</param> /// <param name="text">Text to style</param> /// <param name="startIndex">Style start index</param> /// <param name="endIndex">Style end index</param> public NSMutableAttributedString CreateStyledString(TextStyleParameters style, string text, int startIndex = 0, int endIndex = -1) { var attribs = GetStringAttributes(style, DefaultTextSize); text = ParseString(style, text); if (endIndex == -1) { endIndex = text.Length; } var prettyString = new NSMutableAttributedString(text); prettyString.SetAttributes(attribs, new NSRange(startIndex, endIndex)); return(prettyString); }
/// <summary> /// End the specified tag /// </summary> /// <param name="style">TextStyleParameters</param> /// <param name="text">SpannableStringBuilder</param> /// <param name="kind">Class</param> /// <param name="newSpan">Java.Lang.Object</param> static void End(TextStyleParameters style, SpannableStringBuilder text, Class kind, Java.Lang.Object newSpan) { var length = text.Length(); var span = GetLast(text, kind); var start = text.GetSpanStart(span); text.RemoveSpan(span); // Parse the text in the span var parsedString = TextStyle.ParseString(style, text.SubSequence(start, length)); // Note this hardcodes the text this way and only works on parsed tags! text.Replace(start, length, parsedString); if (start != length) { text.SetSpan(newSpan, start, length, SpanTypes.InclusiveExclusive); } }
/// <summary> /// Merges a css rule. /// </summary> /// <returns>The rule.</returns> /// <param name="curStyle">Target TextStyleParameters</param> /// <param name="css">Css value</param> /// <param name="clone">If set to <c>true</c> clone the style</param> public static TextStyleParameters MergeRule(TextStyleParameters curStyle, string css, bool clone) { var parser = new CssParser(); var rules = parser.ParseAll(css); if (rules.Count() != 1) { throw new NotSupportedException("Only a single css class may be merged at a time"); } var mergedStyle = clone ? curStyle.Clone() : curStyle; var rule = rules.FirstOrDefault(); if (rule != null) { ParseCSSRule(ref mergedStyle, rule, null); } return(mergedStyle); }
public static Dictionary <string, TextStyleParameters> Parse(CssRuleSet ruleSet) { var textStyles = new Dictionary <string, TextStyleParameters>(); // Process all the rules foreach (var rule in ruleSet.Rules) { // Process each rule foreach (var selector in rule.Selectors) { // If it doesnt exist, create it if (!textStyles.ContainsKey(selector)) { textStyles[selector] = new TextStyleParameters(selector); } var curStyle = textStyles[selector]; ParseCSSRule(ref curStyle, rule, ruleSet.Variables); } } return(textStyles); }
public static bool RequiresHtmlTags(this TextStyleParameters target) { if (target.TextDecoration != CssDecoration.None) { return(true); } if (Math.Abs(target.LetterSpacing) > 0) { return(true); } if (target.FontStyle == CssFontStyle.Italic) { return(true); } if (target.FontWeight == CssFontWeight.Bold) { return(true); } return(false); }
internal static UIStringAttributes GetStringAttributes(TextStyleParameters style, float defaultTextSize) { var stringAttribs = new UIStringAttributes(); var fontSize = style.FontSize; if (fontSize <= 0f) { fontSize = defaultTextSize; } if (!string.IsNullOrEmpty(style.Font)) { stringAttribs.Font = UIFont.FromName(style.Font, fontSize); } if (style.Color != ColorRGB.Empty) { stringAttribs.ForegroundColor = style.Color.ToNative(); } if (style.Color != ColorRGB.Empty) { stringAttribs.BackgroundColor = style.BackgroundColor.ToNative(); } if (style.LetterSpacing > 0f) { stringAttribs.KerningAdjustment = style.LetterSpacing; } // Does nothing on the string attribs, needs to be part of a NSMutableAttributedString if (style.LineHeight != 0f) { var paragraphStyle = new NSMutableParagraphStyle() { LineHeightMultiple = style.LineHeight / fontSize, Alignment = GetAlignment(style.TextAlign) }; stringAttribs.ParagraphStyle = paragraphStyle; } if (style.TextDecoration != CssDecoration.None) { switch (style.TextDecoration) { case CssDecoration.LineThrough: stringAttribs.StrikethroughStyle = NSUnderlineStyle.Single; break; case CssDecoration.Underline: stringAttribs.UnderlineStyle = NSUnderlineStyle.Single; break; } if (!string.IsNullOrEmpty(style.TextDecorationColor)) { stringAttribs.StrikethroughColor = UIColor.Clear.FromHex(style.TextDecorationColor); } } return(stringAttribs); }
/// <summary> /// Parses to CSS string. /// </summary> /// <returns>The to CSS string.</returns> /// <param name="tagName">Tag name.</param> /// <param name="style">Style.</param> public static string ParseToCSSString(string tagName, TextStyleParameters style) { var builder = new StringBuilder(); builder.Append(tagName + "{"); string cast; var runtimeProperties = style.GetType().GetRuntimeProperties(); foreach (var prop in runtimeProperties) { try { var value = prop.GetValue(style); if (value != null) { string parsedValue = null; switch (prop.PropertyType.Name) { case "String": if ((value as string).StartsWith("#")) { parsedValue = (string)value; } else { parsedValue = "'" + value + "'"; } break; case "Single": if (Convert.ToSingle(value) > float.MinValue) { parsedValue = Convert.ToString(value); if (prop.Name == "FontSize") // Dirty, I really need a list of things that can be set in pixel values { parsedValue += "px"; } } break; case "Int32": if (Convert.ToInt32(value) > int.MinValue) { parsedValue = Convert.ToString(value); } break; case "Single[]": parsedValue = Convert.ToString(value); break; case "CssAlign": case "CssDecoration": case "CssTextTransform": case "CssTextOverflow": cast = Convert.ToString(value); if (cast != "None") { parsedValue = cast.ToLower(); } break; case "CssFontStyle": case "CssFontWeight": cast = Convert.ToString(value); if (cast != "Normal") { parsedValue = cast.ToLower(); } break; case "ColorRGB": var colorRGB = (ColorRGB)value; cast = colorRGB.ToString(); break; default: throw new InvalidCastException("Could not find the appropriate type " + prop.PropertyType.Name); } var attributes = (CssAttribute[])prop.GetCustomAttributes( typeof(CssAttribute), false); if (attributes.Length > 0 && parsedValue != null) { builder.Append(attributes[0].Name + ":" + parsedValue + ";"); } } } catch (Exception ex) { throw ex; } } builder.Append("}"); return(builder.ToString()); }
// TODO implement this function for styling plain text views, for html based views perhaps not internal void StyleTextView(TextView target, TextStyleParameters style, bool isPlainText, bool ignoreHtml = false) { var fontSize = (style.FontSize <= 0f) ? DefaultTextSize : style.FontSize; target.SetTextSize(ComplexUnitType.Sp, fontSize); // Plain text fonts and colors if (isPlainText) { if (style.Color != ColorRGB.Empty) { target.SetTextColor(style.Color.ToNative()); } if (!String.IsNullOrEmpty(style.Font) && _typeFaces.ContainsKey(style.Font)) { target.Typeface = _typeFaces[style.Font]; target.PaintFlags = target.PaintFlags | PaintFlags.SubpixelText; } } // Lines if (style.Lines > 0) { target.SetLines(style.Lines); } if (style.BackgroundColor != ColorRGB.Empty) { target.SetBackgroundColor(style.BackgroundColor.ToNative()); } // Does nothing on the string attribs, needs to be part of a NSMutableAttributedString if (Math.Abs(style.LineHeight) > 0) { target.SetLineSpacing(0, style.LineHeight / fontSize); } // Assing the text gravity target.TextAlignment = TextAlignment.Gravity; switch (style.TextAlign) { case CssAlign.Center: target.Gravity = GravityFlags.CenterHorizontal; break; case CssAlign.Justified: target.Gravity = GravityFlags.FillHorizontal; break; case CssAlign.Right: target.Gravity = GravityFlags.Right; break; default: target.Gravity = GravityFlags.Left; break; } // Padding target.SetPadding( (style.PaddingLeft > float.MinValue) ? (int)style.PaddingLeft : target.PaddingLeft, (style.PaddingTop > float.MinValue) ? (int)style.PaddingTop : target.PaddingTop, (style.PaddingRight > float.MinValue) ? (int)style.PaddingRight : target.PaddingRight, (style.PaddingBottom > float.MinValue) ? (int)style.PaddingBottom : target.PaddingBottom ); // Overflow // TODO implement this fully switch (style.TextOverflow) { case CssTextOverflow.Ellipsis: target.Ellipsize = TextUtils.TruncateAt.End; break; default: break; } }
public CustomTypefaceSpan(String family, Typeface typeface, TextStyleParameters style) : base(family) { _typeface = typeface; _style = style; }
/// <summary> /// Parses the CSS rule. /// </summary> /// <param name="curStyle">Current style.</param> /// <param name="rule">Rule.</param> internal static void ParseCSSRule(ref TextStyleParameters curStyle, CssParserRule rule, Dictionary <string, string> cssVariables) { foreach (var declaration in rule.Declarations) { if (_textStyleProperties.ContainsKey(declaration.Property)) { // Assign the variable if it exists if (cssVariables != null && declaration.ReferencesVariable) { declaration.Value = cssVariables[declaration.Value]; } var cleanedValue = declaration.Value.Replace("\"", ""); cleanedValue = cleanedValue.Trim(); var prop = _textStyleProperties[declaration.Property]; switch (prop.PropertyType.Name) { case "String": curStyle.SetValue(prop.Name, cleanedValue); break; case "Int32": int numInt; if (int.TryParse(cleanedValue, out numInt)) { curStyle.SetValue(prop.Name, numInt); } break; case "Single": cleanedValue = cleanedValue.Replace("px", ""); float numFloat; if (float.TryParse(cleanedValue, out numFloat)) { curStyle.SetValue(prop.Name, numFloat); } else { throw new Exception("Failed to Parse Single value " + cleanedValue); } break; case "Single[]": var parts = cleanedValue.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); var parsedValues = new float[parts.Length]; for (int i = 0; i < parts.Length; i++) { float numArrayFloat; if (float.TryParse(parts[i], out numArrayFloat)) { parsedValues[i] = numArrayFloat; } } curStyle.SetValue(prop.Name, parsedValues); break; case "ColorRGB": curStyle.SetValue(prop.Name, ColorRGB.FromHex(cleanedValue)); break; case "CssAlign": curStyle.TextAlign = EnumUtils.FromDescription <CssAlign>(cleanedValue); break; case "CssDecoration": curStyle.TextDecoration = EnumUtils.FromDescription <CssDecoration>(cleanedValue); break; case "CssTextTransform": curStyle.TextTransform = EnumUtils.FromDescription <CssTextTransform>(cleanedValue); break; case "CssTextOverflow": curStyle.TextOverflow = EnumUtils.FromDescription <CssTextOverflow>(cleanedValue); break; case "CssFontStyle": curStyle.FontStyle = EnumUtils.FromDescription <CssFontStyle>(cleanedValue); break; case "CssFontWeight": curStyle.FontWeight = EnumUtils.FromDescription <CssFontWeight>(cleanedValue); break; default: throw new InvalidCastException("Could not find the appropriate type " + prop.PropertyType.Name); } } } }