// Takes a string and replaces the content of the paragraph with it. private void SetText(string text, string activeUrl) { foreach (IUIControl control in ChildControls) { control.RemoveFromView(ParentEditingCanvas); } ChildControls.Clear( ); // give the text a style that doesn't include things it shouldn't inherit Styles.Style textStyle = mStyle; textStyle.mBorderColor = null; textStyle.mBorderRadius = null; textStyle.mBorderWidth = null; // now break it into words so we can do word wrapping string[] words = text.Split(' '); foreach (string word in words) { // create labels out of each one if (string.IsNullOrEmpty(word) == false) { // if the last thing we added was a special control like a reveal box, we // need the first label after that to have a leading space so it doesn't bunch up against // the control string nextWord = word; NoteText wordLabel = Parser.CreateNoteText(new CreateParams(this, Frame.Width, Frame.Height, ref textStyle), nextWord + " "); ChildControls.Add(wordLabel); } } if (activeUrl.Trim( ) != EditableConfig.sPlaceholderUrlText && string.IsNullOrWhiteSpace(activeUrl) == false) { // help them out by adding 'https://' if it isn't there. if (activeUrl.StartsWith("https") == false && BibleRenderer.IsBiblePrefix(activeUrl) == false) { activeUrl = activeUrl.Insert(0, "https://"); } ActiveUrl = activeUrl; } else { ActiveUrl = null; } TryAddUrlGlyph(Frame.Width, Frame.Height); }
public void TryAddUrlGlyph(float parentWidth, float parentHeight) { if (string.IsNullOrEmpty(ActiveUrl) == false) { // give the text a style that doesn't include things it shouldn't inherit Styles.Style textStyle = mStyle; textStyle.mBorderColor = 0; textStyle.mBorderRadius = 0; textStyle.mBorderWidth = 0; textStyle.mFont.mColor = mStyle.mFont.mColor ?? ControlStyles.mText.mFont.mColor; textStyle.mFont.mName = PrivateControlStylingConfig.Icon_Font_Secondary; textStyle.mFont.mSize = mStyle.mFont.mSize ?? ControlStyles.mText.mFont.mSize; textStyle.mAlignment = Alignment.Right; NoteText wordLabel = Parser.CreateNoteText(new CreateParams(this, parentWidth, parentHeight, ref textStyle), PrivateNoteConfig.CitationUrl_Icon); ChildControls.Add(wordLabel); } }
public void AddControl(UserControl uc, List <Control> childlist) { if (ChildControls != null) { ChildControls.Add(uc); } else { ChildControls = new List <Control>() { uc } }; multiViewRestrict.ActiveViewIndex = 1; NoOfChildRestrictionSets = NoOfChildRestrictionSets + 1; pnlRestrictions.Controls.Add(uc); }
//used public void AddControl(Control uc, List <Control> childlist = null) { if (ChildControls != null) { ChildControls.Add(uc); } else { ChildControls = new List <Control>() { uc } }; multiViewRestrict.ActiveViewIndex = 1; lnkAddActOrRes.Attributes.Add("name", hidRelativeId.Value + "-" + NoOfChildRestrictionSets); NoOfChildRestrictionSets = NoOfChildRestrictionSets + 1; pnlRestrictions.Controls.Add(uc); }
public void AddControls(List <Control> ucList, List <Control> childlist) { foreach (var uc in ucList) { if (ChildControls != null) { ChildControls.Add(uc); } else { ChildControls = new List <Control>() { uc } }; multiViewRestrict.ActiveViewIndex = 1; NoOfChildRestrictionSets = NoOfChildRestrictionSets + 1; pnlRestrictions.Controls.Add(uc); } }
public StackPanel(CreateParams parentParams, XmlReader reader) { Initialize( ); // Always get our style first mStyle = parentParams.Style; Styles.Style.ParseStyleAttributesWithDefaults(reader, ref mStyle, ref ControlStyles.mStackPanel); // check for attributes we support RectangleF bounds = new RectangleF( ); SizeF parentSize = new SizeF(parentParams.Width, parentParams.Height); ParseCommonAttribs(reader, ref parentSize, ref bounds); // Get margins and padding RectangleF padding; RectangleF margin; GetMarginsAndPadding(ref mStyle, ref parentSize, ref bounds, out margin, out padding); // apply margins to as much of the bounds as we can (bottom must be done by our parent container) ApplyImmediateMargins(ref bounds, ref margin, ref parentSize); Margin = margin; // check for border styling int borderPaddingPx = 0; if (mStyle.mBorderColor.HasValue) { BorderView.BorderColor = mStyle.mBorderColor.Value; } if (mStyle.mBorderRadius.HasValue) { BorderView.CornerRadius = mStyle.mBorderRadius.Value; } if (mStyle.mBorderWidth.HasValue) { BorderView.BorderWidth = mStyle.mBorderWidth.Value; borderPaddingPx = (int)Rock.Mobile.Graphics.Util.UnitToPx(mStyle.mBorderWidth.Value + PrivateNoteConfig.BorderPadding); } if (mStyle.mBackgroundColor.HasValue) { BorderView.BackgroundColor = mStyle.mBackgroundColor.Value; } // // now calculate the available width based on padding. (Don't actually change our width) float availableWidth = bounds.Width - padding.Left - padding.Width - (borderPaddingPx * 2); // now read what our children's alignment should be // check for alignment string result = reader.GetAttribute("ChildAlignment"); if (string.IsNullOrEmpty(result) == false) { switch (result) { case "Left": { ChildHorzAlignment = Alignment.Left; break; } case "Right": { ChildHorzAlignment = Alignment.Right; break; } case "Center": { ChildHorzAlignment = Alignment.Center; break; } default: { ChildHorzAlignment = mStyle.mAlignment.Value; break; } } } else { // if it wasn't specified, use left alignment. ChildHorzAlignment = Alignment.Left; } // Parse Child Controls bool finishedParsing = false; while (finishedParsing == false && reader.Read( )) { switch (reader.NodeType) { case XmlNodeType.Element: { // let each child have our available width. Style style = new Style( ); style = mStyle; style.mAlignment = ChildHorzAlignment; IUIControl control = Parser.TryParseControl(new CreateParams(this, availableWidth, parentParams.Height, ref style), reader); if (control != null) { ChildControls.Add(control); } break; } case XmlNodeType.EndElement: { // if we hit the end of our label, we're done. //if( reader.Name == "StackPanel" || reader.Name == "SP" ) if (ElementTagMatches(reader.Name)) { finishedParsing = true; } break; } } } LayoutStackPanel(bounds, padding.Left, padding.Top, availableWidth, padding.Height, borderPaddingPx); }
public Paragraph(CreateParams parentParams, XmlReader reader) { Initialize( ); // Always get our style first mStyle = parentParams.Style; Styles.Style.ParseStyleAttributesWithDefaults(reader, ref mStyle, ref ControlStyles.mParagraph); // check for attributes we support RectangleF bounds = new RectangleF( ); SizeF parentSize = new SizeF(parentParams.Width, parentParams.Height); ParseCommonAttribs(reader, ref parentSize, ref bounds); // Get margins and padding RectangleF padding; RectangleF margin; GetMarginsAndPadding(ref mStyle, ref parentSize, ref bounds, out margin, out padding); // apply margins to as much of the bounds as we can (bottom must be done by our parent container) ApplyImmediateMargins(ref bounds, ref margin, ref parentSize); Margin = margin; // check for border styling int borderPaddingPx = 0; if (mStyle.mBorderColor.HasValue) { BorderView.BorderColor = mStyle.mBorderColor.Value; } if (mStyle.mBorderRadius.HasValue) { BorderView.CornerRadius = mStyle.mBorderRadius.Value; } if (mStyle.mBorderWidth.HasValue) { BorderView.BorderWidth = mStyle.mBorderWidth.Value; borderPaddingPx = (int)Rock.Mobile.Graphics.Util.UnitToPx(mStyle.mBorderWidth.Value + PrivateNoteConfig.BorderPadding); } if (mStyle.mBackgroundColor.HasValue) { BorderView.BackgroundColor = mStyle.mBackgroundColor.Value; } // // now calculate the available width based on padding. (Don't actually change our width) float availableWidth = bounds.Width - padding.Left - padding.Width - (borderPaddingPx * 2); // see if there's a URL we should care about ActiveUrl = reader.GetAttribute("Url"); string urlLaunchesExternalBrowser = reader.GetAttribute("UrlLaunchesExternalBrowser"); if (string.IsNullOrEmpty(urlLaunchesExternalBrowser) == false) { UrlLaunchesExternalBrowser = bool.Parse(urlLaunchesExternalBrowser); } string urlUsesRockImpersonation = reader.GetAttribute("UrlUsesRockImpersonation"); if (string.IsNullOrEmpty(urlUsesRockImpersonation) == false) { UrlUsesRockImpersonation = bool.Parse(urlUsesRockImpersonation); } // now read what our children's alignment should be // check for alignment string result = reader.GetAttribute("ChildAlignment"); if (string.IsNullOrEmpty(result) == false) { switch (result) { case "Left": { ChildHorzAlignment = Alignment.Left; break; } case "Right": { ChildHorzAlignment = Alignment.Right; break; } case "Center": { ChildHorzAlignment = Alignment.Center; break; } default: { ChildHorzAlignment = mStyle.mAlignment.Value; break; } } } else { // if it wasn't specified, use LEFT alignment. ChildHorzAlignment = Alignment.Left; } bool removedLeadingWhitespace = false; bool lastControlWasElement = false; bool finishedReading = false; while (finishedReading == false && reader.Read( )) { switch (reader.NodeType) { case XmlNodeType.Element: { IUIControl control = Parser.TryParseControl(new CreateParams(this, availableWidth, parentParams.Height, ref mStyle), reader); if (control != null) { // if the last control was an element (NoteText or Reveal), then we have two in a row. So place a space between them! if (lastControlWasElement) { NoteText textLabel = Parser.CreateNoteText(new CreateParams(this, availableWidth, parentParams.Height, ref mStyle), " "); ChildControls.Add(textLabel); } // only allow RevealBoxes / NoteText as children. if (control as RevealBox == null && control as NoteText == null) { throw new Exception(String.Format("Paragraph only supports children of type <RevealBox> or <NoteText>. Found <{0}>", control.GetType( ))); } ChildControls.Add(control); // flag that whitespace is removed, because either // this was the first control and we didn't want to, or // it was removed by the first text we created. removedLeadingWhitespace = true; // flag that the last control placed was a reveal, so that // should we come across another one immediately, we know to insert a space // so they don't render concatenated. lastControlWasElement = true; } break; } case XmlNodeType.Text: { // give the text a style that doesn't include things it shouldn't inherit Styles.Style textStyle = mStyle; textStyle.mBorderColor = null; textStyle.mBorderRadius = null; textStyle.mBorderWidth = null; // grab the text. remove any weird characters string text = Regex.Replace(reader.Value, @"\t|\n|\r", ""); if (removedLeadingWhitespace == false) { removedLeadingWhitespace = true; text = text.TrimStart(' '); } // now break it into words so we can do word wrapping string[] words = text.Split(' '); foreach (string word in words) { // create labels out of each one if (string.IsNullOrEmpty(word) == false) { // if the last thing we added was a special control like a reveal box, we // need the first label after that to have a leading space so it doesn't bunch up against // the control string nextWord = word; if (lastControlWasElement) { nextWord = word.Insert(0, " "); lastControlWasElement = false; } NoteText wordLabel = Parser.CreateNoteText(new CreateParams(this, availableWidth, parentParams.Height, ref textStyle), nextWord + " "); ChildControls.Add(wordLabel); } } lastControlWasElement = false; break; } case XmlNodeType.EndElement: { // if we hit the end of our label, we're done. //if( reader.Name == "Paragraph" || reader.Name == "P" ) if (ElementTagMatches(reader.Name)) { finishedReading = true; } break; } } } // should we add a URL Glyph? We're gonna be clever and add it AS a NoteText, so that it integrates with the paragraph nicely. // now add our glyph, if relevant TryAddUrlGlyph(availableWidth, parentParams.Height); // layout all controls // paragraphs are tricky. // We need to lay out controls horizontally and wrap when we run out of room. // To align, we need to keep track of each "row". When the row is full, // we calculate its width, and then adjust each item IN that row so // that the row is centered within the max width of the paragraph. // The max width of the paragraph is defined as the widest row. // maintain a list of all our rows so that once they are all generated, // we can align them based on the widest row. float maxRowWidth = 0; List <List <IUIControl> > rowList = new List <List <IUIControl> >( ); // track where within a row we need to start a control float rowRemainingWidth = availableWidth; float startingX = bounds.X + padding.Left + borderPaddingPx; // always store the last placed control's height so that should // our NEXT control need to wrap, we know how far down to wrap. float yOffset = bounds.Y + padding.Top + borderPaddingPx; float lastControlHeight = 0; float rowWidth = 0; //Create our first row and put it in our list List <IUIControl> currentRow = new List <IUIControl>( ); rowList.Add(currentRow); foreach (IUIControl control in ChildControls) { RectangleF controlFrame = control.GetFrame( ); // if there is NOT enough room on this row for the next control if (rowRemainingWidth < controlFrame.Width) { // since we're advancing to the next row, trim leading white space, which, if we weren't wrapping, // would be a space between words. // note: we can safely cast to a NoteText because that's the only child type we allow. string text = ((NoteText)control).GetText( ).TrimStart(' '); ((NoteText)control).SetText(text); // advance to the next row yOffset += lastControlHeight; // Reset values for the new row rowRemainingWidth = availableWidth; startingX = bounds.X + padding.Left + borderPaddingPx; lastControlHeight = 0; rowWidth = 0; currentRow = new List <IUIControl>( ); rowList.Add(currentRow); } // Add this next control to the current row currentRow.Add(control); // position this control appropriately control.AddOffset(startingX, yOffset); // update so the next child begins beyond this one. // also reduce the available width by this control's. rowWidth += controlFrame.Width; startingX += controlFrame.Width; //Increment startingX so the next control is placed after this one. rowRemainingWidth -= controlFrame.Width; //Reduce the available width by what this control took. lastControlHeight = controlFrame.Height > lastControlHeight ? controlFrame.Height : lastControlHeight; //Store the height of the tallest control on this row. // track the widest row maxRowWidth = rowWidth > maxRowWidth ? rowWidth : maxRowWidth; } // give each row the legal bounds it may work with RectangleF availableBounds = new RectangleF(bounds.X + padding.Left + borderPaddingPx, bounds.Y + borderPaddingPx + padding.Top, availableWidth, bounds.Height); // Now that we know the widest row, align all the rows foreach (List <IUIControl> row in rowList) { AlignRow(availableBounds, row, maxRowWidth); } // Build our final frame that determines our dimensions RectangleF frame = new RectangleF(65000, 65000, -65000, -65000); // for each child control foreach (IUIControl control in ChildControls) { // enlarge our frame by the current frame and the next child frame = Parser.CalcBoundingFrame(frame, control.GetFrame( )); } frame.Y = bounds.Y; frame.X = bounds.X; frame.Height += padding.Height + padding.Top + (borderPaddingPx * 2); //add in padding frame.Width = bounds.Width; // setup our bounding rect for the border frame = new RectangleF(frame.X, frame.Y, frame.Width, frame.Height); // and store that as our bounds BorderView.Frame = frame; Frame = frame; SetDebugFrame(Frame); // sort everything ChildControls.Sort(BaseControl.Sort); }
public Canvas(CreateParams parentParams, XmlReader reader) { Initialize( ); // Always get our style first mStyle = parentParams.Style; Styles.Style.ParseStyleAttributesWithDefaults(reader, ref mStyle, ref ControlStyles.mCanvas); // check for attributes we support RectangleF bounds = new RectangleF( ); SizeF parentSize = new SizeF(parentParams.Width, parentParams.Height); ParseCommonAttribs(reader, ref parentSize, ref bounds); // Get margins and padding RectangleF padding; RectangleF margin; GetMarginsAndPadding(ref mStyle, ref parentSize, ref bounds, out margin, out padding); // apply margins to as much of the bounds as we can (bottom must be done by our parent container) ApplyImmediateMargins(ref bounds, ref margin, ref parentSize); Margin = margin; // check for border styling int borderPaddingPx = 0; if (mStyle.mBorderColor.HasValue) { BorderView.BorderColor = mStyle.mBorderColor.Value; } if (mStyle.mBorderRadius.HasValue) { BorderView.CornerRadius = mStyle.mBorderRadius.Value; } if (mStyle.mBorderWidth.HasValue) { BorderView.BorderWidth = mStyle.mBorderWidth.Value; borderPaddingPx = (int)Rock.Mobile.Graphics.Util.UnitToPx(mStyle.mBorderWidth.Value + PrivateNoteConfig.BorderPadding); } if (mStyle.mBackgroundColor.HasValue) { BorderView.BackgroundColor = mStyle.mBackgroundColor.Value; } // // now calculate the available width based on padding. (Don't actually change our width) float availableWidth = bounds.Width - padding.Left - padding.Width - (borderPaddingPx * 2); // now read what our children's alignment should be // check for alignment string result = reader.GetAttribute("ChildAlignment"); if (string.IsNullOrEmpty(result) == false) { switch (result) { case "Left": ChildHorzAlignment = Alignment.Left; break; case "Right": ChildHorzAlignment = Alignment.Right; break; case "Center": ChildHorzAlignment = Alignment.Center; break; default: ChildHorzAlignment = mStyle.mAlignment.Value; break; } } else { // if it wasn't specified, use OUR alignment. ChildHorzAlignment = mStyle.mAlignment.Value; } // Parse Child Controls bool finishedParsing = false; while (finishedParsing == false && reader.Read( )) { switch (reader.NodeType) { case XmlNodeType.Element: { // let each child have our available width. Style style = new Style( ); style = mStyle; style.mAlignment = ChildHorzAlignment; IUIControl control = Parser.TryParseControl(new CreateParams(this, availableWidth, parentParams.Height, ref style), reader); if (control != null) { ChildControls.Add(control); } break; } case XmlNodeType.EndElement: { // if we hit the end of our label, we're done. //if( reader.Name == "Canvas" || reader.Name == "C" ) if (ElementTagMatches(reader.Name)) { finishedParsing = true; } break; } } } // layout all controls float yOffset = bounds.Y + padding.Top + borderPaddingPx; //vertically they should just stack float height = 0; // now we must center each control within the stack. foreach (IUIControl control in ChildControls) { RectangleF controlFrame = control.GetFrame( ); RectangleF controlMargin = control.GetMargin( ); // horizontally position the controls according to their // requested alignment Alignment controlAlignment = control.GetHorzAlignment( ); // adjust by our position float xAdjust = 0; switch (controlAlignment) { case Alignment.Center: xAdjust = bounds.X + ((availableWidth / 2) - (controlFrame.Width / 2)); break; case Alignment.Right: xAdjust = bounds.X + (availableWidth - (controlFrame.Width + controlMargin.Width)); break; case Alignment.Left: xAdjust = bounds.X; break; } // adjust the next sibling by yOffset control.AddOffset(xAdjust + padding.Left + borderPaddingPx, yOffset); // track the height of the grid by the control lowest control height = (control.GetFrame( ).Bottom + +controlMargin.Height) > height ? (control.GetFrame( ).Bottom + +controlMargin.Height) : height; } // we need to store our bounds. We cannot // calculate them on the fly because we // would lose any control defined offsets, which would throw everything off. bounds.Height = height + padding.Height + borderPaddingPx; // setup our bounding rect for the border bounds = new RectangleF(bounds.X, bounds.Y, bounds.Width, bounds.Height); // and store that as our bounds BorderView.Frame = bounds; Frame = bounds; // store our debug frame SetDebugFrame(Frame); // sort everything ChildControls.Sort(BaseControl.Sort); }
public ListItem(CreateParams parentParams, XmlReader reader) { // verify that our parent is a list. That's the only acceptable place for us. if ((parentParams.Parent as List) == null) { throw new Exception(string.Format("<ListItem> parent must be <List>. This <ListItem> parent is: <{0}>", parentParams.Parent.GetType())); } Initialize( ); // Always get our style first mStyle = parentParams.Style; Styles.Style.ParseStyleAttributesWithDefaults(reader, ref mStyle, ref ControlStyles.mListItem); mStyle.mAlignment = null; //don't use alignment // check for attributes we support RectangleF bounds = new RectangleF( ); SizeF parentSize = new SizeF(parentParams.Width, parentParams.Height); ParseCommonAttribs(reader, ref parentSize, ref bounds); //ignore positioning attributes. bounds = new RectangleF( ); bounds.Width = parentParams.Width; // Get margins and padding RectangleF padding; RectangleF margin; GetMarginsAndPadding(ref mStyle, ref parentSize, ref bounds, out margin, out padding); // apply margins to as much of the bounds as we can (bottom must be done by our parent container) ApplyImmediateMargins(ref bounds, ref margin, ref parentSize); Margin = margin; // check for border styling int borderPaddingPx = 0; if (mStyle.mBorderColor.HasValue) { BorderView.BorderColor = mStyle.mBorderColor.Value; } if (mStyle.mBorderRadius.HasValue) { BorderView.CornerRadius = mStyle.mBorderRadius.Value; } if (mStyle.mBorderWidth.HasValue) { BorderView.BorderWidth = mStyle.mBorderWidth.Value; borderPaddingPx = (int)Rock.Mobile.Graphics.Util.UnitToPx(mStyle.mBorderWidth.Value + PrivateNoteConfig.BorderPadding); } if (mStyle.mBackgroundColor.HasValue) { BorderView.BackgroundColor = mStyle.mBackgroundColor.Value; } // // now calculate the available width based on padding. (Don't actually change our width) float availableWidth = bounds.Width - padding.Left - padding.Width - (borderPaddingPx * 2); // Parse Child Controls bool finishedParsing = false; while (finishedParsing == false && reader.Read( )) { switch (reader.NodeType) { case XmlNodeType.Element: { // let each child have our available width. IUIControl control = Parser.TryParseControl(new CreateParams(this, availableWidth, parentParams.Height, ref mStyle), reader); if (control != null) { ChildControls.Add(control); } break; } case XmlNodeType.Text: { // grab the text. remove any weird characters string text = Regex.Replace(reader.Value, @"\t|\n|\r", ""); // now break it into words so we can do word wrapping string[] words = text.Split(' '); // the very very first word gets a bullet point! string sentence = ""; foreach (string word in words) { // create labels out of each one if (string.IsNullOrEmpty(word) == false) { sentence += word + " "; } } NoteText textLabel = Parser.CreateNoteText(new CreateParams(this, availableWidth, parentParams.Height, ref mStyle), sentence); ChildControls.Add(textLabel); break; } case XmlNodeType.EndElement: { // if we hit the end of our label, we're done. //if( reader.Name == "ListItem" || reader.Name == "LI" ) if (ElementTagMatches(reader.Name)) { finishedParsing = true; } break; } } } LayoutStackPanel(bounds, padding.Left, padding.Top, availableWidth, padding.Height, borderPaddingPx); }
public void HandleCreateControl(Type controlType, PointF mousePos) { do { // first, if we're creating a header, we need to make sure there isn't already one if (typeof(EditableHeader) == controlType) { List <IUIControl> headerControls = new List <IUIControl>( ); GetControlOfType <EditableHeader>(headerControls); // we found a header, so we're done. if (headerControls.Count > 0) { break; } } // now see if any child wants to create it IUIControl newControl = null; foreach (IUIControl control in ChildControls) { IEditableUIControl editableControl = control as IEditableUIControl; if (editableControl != null) { IEditableUIControl containerControl = editableControl.ContainerForControl(controlType, mousePos); if (containerControl != null) { newControl = containerControl.HandleCreateControl(controlType, mousePos); break; } } } // if a child handled it, we're done if (newControl != null) { break; } // it wasn't a header, and a child didn't create it, so we will. float availableWidth = Frame.Width - Padding.Right - Padding.Left; // if the control type is a header, we want to force it to position 0 float workingWidth = availableWidth; if (typeof(EditableHeader) == controlType) { mousePos = PointF.Empty; // and if its allowed, use the full width if (mStyle.mFullWidthHeader == true) { workingWidth = Frame.Width; } } newControl = Parser.CreateEditableControl(controlType, new BaseControl.CreateParams(this, workingWidth, DeviceHeight, ref mStyle)); ChildControls.Add(newControl); // add it to our renderable canvas newControl.AddToView(MasterView); // default it to where the click occurred newControl.AddOffset((float)mousePos.X, (float)mousePos.Y); // if the newly created control is the lower than all others, update the note height. // This lets us continue to build vertically if (newControl.GetFrame( ).Bottom > Frame.Height) { Frame = new RectangleF(Frame.Left, Frame.Top, Frame.Width, newControl.GetFrame( ).Bottom + Padding.Bottom); } }while(0 != 0); }
void ParseNote(XmlReader reader, float parentWidthUnits, float parentHeightUnits) { DeviceHeight = parentHeightUnits; // get the style first Styles.Style.ParseStyleAttributesWithDefaults(reader, ref mStyle, ref ControlStyles.mMainNote); // check for attributes we support RectangleF bounds = new RectangleF( ); SizeF parentSize = new SizeF(parentWidthUnits, parentHeightUnits); Parser.ParseBounds(reader, ref parentSize, ref bounds); // Parent note doesn't support margins. // PADDING float leftPadding = Styles.Style.GetValueForNullable(mStyle.mPaddingLeft, parentWidthUnits, 0); float rightPadding = Styles.Style.GetValueForNullable(mStyle.mPaddingRight, parentWidthUnits, 0); float topPadding = Styles.Style.GetValueForNullable(mStyle.mPaddingTop, parentHeightUnits, 0); float bottomPadding = Styles.Style.GetValueForNullable(mStyle.mPaddingBottom, parentHeightUnits, 0); Padding = new RectangleF(leftPadding, rightPadding, topPadding, bottomPadding); // now calculate the available width based on padding. (Don't actually change our width) float availableWidth = parentWidthUnits - leftPadding - rightPadding; // A "special" (we won't call this a hack) attribute that will enable the user // to have a header container that spans the full width of the note, which allows // it to be unaffected by the padding. string result = reader.GetAttribute("FullWidthHeader"); if (string.IsNullOrEmpty(result) == false) { mStyle.mFullWidthHeader = bool.Parse(result); } // begin reading the xml stream bool finishedReading = false; while (finishedReading == false && reader.Read( )) { switch (reader.NodeType) { case XmlNodeType.Element: { float workingWidth = availableWidth; if (Header.ElementTagMatches(reader.Name) == true && mStyle.mFullWidthHeader == true) { workingWidth = parentWidthUnits; } IUIControl control = Parser.TryParseControl(new BaseControl.CreateParams(this, workingWidth, parentHeightUnits, ref mStyle), reader); ChildControls.Add(control); break; } case XmlNodeType.EndElement: { if (reader.Name == "Note") { finishedReading = true; } break; } } } // lay stuff out vertically. If the notes were built by hand, like a stackPanel. // if not by hand, like a canvas. float noteHeight = bounds.Y + topPadding; foreach (IUIControl control in ChildControls) { RectangleF controlFrame = control.GetFrame( ); RectangleF controlMargin = control.GetMargin( ); // horizontally position the controls according to their // requested alignment Alignment controlAlignment = control.GetHorzAlignment( ); // adjust by our position float xAdjust = 0; switch (controlAlignment) { case Alignment.Center: { xAdjust = bounds.X + ((availableWidth / 2) - (controlFrame.Width / 2)); break; } case Alignment.Right: { xAdjust = bounds.X + (availableWidth - (controlFrame.Width + controlMargin.Width)); break; } case Alignment.Left: { xAdjust = bounds.X; break; } } // place this next control at yOffset. yOffset should be the current noteHeight, which makes each control relative to the one above it. float yOffset = noteHeight; // if it's the header and full width is specified, don't apply padding. if (control as Header != null && mStyle.mFullWidthHeader == true) { control.AddOffset(xAdjust, yOffset); } else { control.AddOffset(xAdjust + leftPadding, yOffset); } // update the note height noteHeight = control.GetFrame( ).Bottom + controlMargin.Height; } bounds.Width = parentWidthUnits; bounds.Height = (noteHeight - bounds.Y) + bottomPadding; Frame = bounds; AddControlsToView( ); }
public void SetStyleValue(EditStyling.Style style, object value) { switch (style) { case EditStyling.Style.BoldParagraph: { // force all children to bold foreach (IUIControl child in ChildControls) { IEditableUIControl editableChild = child as IEditableUIControl; if (editableChild != null) { editableChild.SetStyleValue(EditStyling.Style.FontName, EditableParagraph.sDefaultBoldFontName); } } break; } case EditStyling.Style.BoldItalicizeParagraph: { // force all children to bold foreach (IUIControl child in ChildControls) { IEditableUIControl editableChild = child as IEditableUIControl; if (editableChild != null) { editableChild.SetStyleValue(EditStyling.Style.FontName, EditableParagraph.sDefaultBoldItalicFontName); } } break; } case EditStyling.Style.ItalicizeParagraph: { // force all children to bold foreach (IUIControl child in ChildControls) { IEditableUIControl editableChild = child as IEditableUIControl; if (editableChild != null) { editableChild.SetStyleValue(EditStyling.Style.FontName, EditableParagraph.sDefaultItalicFontName); } } break; } case EditStyling.Style.BulletParagraph: { // create a noteText with the bullet, and then insert it XmlTextReader reader = new XmlTextReader(new StringReader("<NT>" + sBulletChar + "</NT>")); reader.Read( ); IUIControl bulletText = Parser.TryParseControl(new CreateParams(this, ParentSize.Width, ParentSize.Height, ref mStyle), reader); ChildControls.Insert(0, bulletText); SetPosition(Frame.Left, Frame.Top); bulletText.AddToView(ParentEditingCanvas); break; } case EditStyling.Style.UnderlineParagraph: { // to underline the whole thing, we need to make it one big NoteText. // we'll gather all the text, convert it to a single NoteText with Underlined Attribute, // remove the existing children, and replace them with the new single underlined one. // get the full text. we can use the build HTML stream code to do this. string htmlStream = string.Empty; string textStream = string.Empty; BuildHTMLContent(ref htmlStream, ref textStream, new List <IUIControl>( )); // if the last character is a URL glyph, remove it textStream = textStream.Trim(new char[] { ' ', PrivateNoteConfig.CitationUrl_Icon[0] }); XmlTextReader reader = new XmlTextReader(new StringReader("<NT Underlined=\"True\">" + textStream + "</NT>")); reader.Read( ); IUIControl noteText = Parser.TryParseControl(new CreateParams(this, ParentSize.Width, ParentSize.Height, ref mStyle), reader); foreach (IUIControl control in ChildControls) { control.RemoveFromView(ParentEditingCanvas); } ChildControls.Clear( ); ChildControls.Add(noteText); SetPosition(Frame.Left, Frame.Top); noteText.AddToView(ParentEditingCanvas); break; } } }
public List(CreateParams parentParams, XmlReader reader) { Initialize( ); // Always get our style first mStyle = parentParams.Style; Styles.Style.ParseStyleAttributesWithDefaults(reader, ref mStyle, ref ControlStyles.mList); // check for attributes we support RectangleF bounds = new RectangleF( ); SizeF parentSize = new SizeF(parentParams.Width, parentParams.Height); ParseCommonAttribs(reader, ref parentSize, ref bounds); // Get margins and padding RectangleF padding; RectangleF margin; GetMarginsAndPadding(ref mStyle, ref parentSize, ref bounds, out margin, out padding); // apply margins to as much of the bounds as we can (bottom must be done by our parent container) ApplyImmediateMargins(ref bounds, ref margin, ref parentSize); Margin = margin; // check for border styling int borderPaddingPx = 0; if (mStyle.mBorderColor.HasValue) { BorderView.BorderColor = mStyle.mBorderColor.Value; } if (mStyle.mBorderRadius.HasValue) { BorderView.CornerRadius = mStyle.mBorderRadius.Value; } if (mStyle.mBorderWidth.HasValue) { BorderView.BorderWidth = mStyle.mBorderWidth.Value; borderPaddingPx = (int)Rock.Mobile.Graphics.Util.UnitToPx(mStyle.mBorderWidth.Value + PrivateNoteConfig.BorderPadding); } if (mStyle.mBackgroundColor.HasValue) { BorderView.BackgroundColor = mStyle.mBackgroundColor.Value; } // // convert indentation if it's a percentage float listIndentation = mStyle.mListIndention.Value; if (listIndentation < 1) { listIndentation = parentParams.Width * listIndentation; } // now calculate the available width based on padding. (Don't actually change our width) // also consider the indention amount of the list. float availableWidth = bounds.Width - padding.Left - padding.Width - listIndentation - (borderPaddingPx * 2); // parse for the desired list style. Default to Bullet if they didn't put anything. ListType = reader.GetAttribute("Type"); if (string.IsNullOrEmpty(ListType) == true) { ListType = ListTypeBullet; } // Parse Child Controls int numberedCount = 1; // don't force our alignment, borders, bullet style or indentation on children. Style style = new Style( ); style = mStyle; style.mAlignment = null; style.mListIndention = null; style.mListBullet = null; style.mBorderColor = null; style.mBorderRadius = null; style.mBorderWidth = null; bool finishedParsing = false; while (finishedParsing == false && reader.Read( )) { switch (reader.NodeType) { case XmlNodeType.Element: { // Create the prefix for this list item. string listItemPrefixStr = mStyle.mListBullet + " "; if (ListType == ListTypeNumbered) { listItemPrefixStr = numberedCount.ToString() + ". "; } NoteText textLabel = Parser.CreateNoteText(new CreateParams(this, availableWidth, parentParams.Height, ref style), listItemPrefixStr); ChildControls.Add(textLabel); // create our actual child, but throw an exception if it's anything but a ListItem. IUIControl control = Parser.TryParseControl(new CreateParams(this, availableWidth - textLabel.GetFrame().Width, parentParams.Height, ref style), reader); ListItem listItem = control as ListItem; if (listItem == null) { throw new Exception(String.Format("Only a <ListItem> may be a child of a <List>. Found element <{0}>.", control.GetType( ))); } // if it will actually use the bullet point, increment our count. if (listItem.ShouldShowBulletPoint() == true) { numberedCount++; } else { // otherwise give it a blank space, and keep our count the same. textLabel.SetText(" "); } // and finally add the actual list item. ChildControls.Add(control); break; } case XmlNodeType.EndElement: { // if we hit the end of our label, we're done. //if( reader.Name == "List" || reader.Name == "L" ) if (ElementTagMatches(reader.Name)) { finishedParsing = true; } break; } } } // layout all controls float xAdjust = bounds.X + listIndentation; float yOffset = bounds.Y + padding.Top + borderPaddingPx; //vertically they should just stack // we know each child is a NoteText followed by ListItem. So, lay them out // as: * - ListItem // * - ListItem foreach (IUIControl control in ChildControls) { // position the control control.AddOffset(xAdjust + padding.Left + borderPaddingPx, yOffset); RectangleF controlFrame = control.GetFrame( ); RectangleF controlMargin = control.GetMargin( ); // is this the item prefix? if ((control as NoteText) != null) { // and update xAdjust so the actual item starts after. xAdjust += controlFrame.Width; } else { // reset the values for the next line. xAdjust = bounds.X + listIndentation; yOffset = controlFrame.Bottom + controlMargin.Height; } } // we need to store our bounds. We cannot // calculate them on the fly because we // would lose any control defined offsets, which would throw everything off. bounds.Height = (yOffset - bounds.Y) + padding.Height + borderPaddingPx; Frame = bounds; BorderView.Frame = bounds; // store our debug frame SetDebugFrame(Frame); // sort everything ChildControls.Sort(BaseControl.Sort); }