Exemple #1
0
                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);
                }
Exemple #2
0
                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);
                }
Exemple #3
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( );
                }
Exemple #4
0
                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);
                }
Exemple #5
0
                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);
                }