public NewMediumLevelRecordEditor(Plugin p, Record r, SubRecord sr, SubrecordStructure ss)
        {
            this.InitializeComponent();
            Icon = Resources.fosnip;
            SuspendLayout();
            this.sr = sr;
            this.ss = ss;
            this.p = p;
            this.r = r;

            // walk each element in standard fashion
            int panelOffset = 0;
            try
            {
                this.fpanel1.ColumnStyles[0] = new ColumnStyle(SizeType.Percent, 100.0f);
                int maxWidth = this.fpanel1.Width - SystemInformation.VerticalScrollBarWidth - 8;
                int leftOffset = 0; // 8;
                foreach (var elem in ss.elements)
                {
                    Control c = null;
                    if (elem.options != null && elem.options.Length > 1)
                    {
                        c = new OptionsElement();
                    }
                    else if (elem.flags != null && elem.flags.Length > 1)
                    {
                        c = new FlagsElement();
                    }
                    else
                    {
                        switch (elem.type)
                        {
                            case ElementValueType.LString:
                                c = new LStringElement();
                                break;
                            case ElementValueType.FormID:
                                c = new FormIDElement();
                                break;
                            case ElementValueType.Blob:
                                c = new HexElement();
                                break;
                            default:
                                c = new TextElement();
                                break;
                        }
                    }

                    if (c is IElementControl)
                    {
                        var ec = c as IElementControl;
                        ec.formIDLookup = p.GetRecordByID;
                        ec.formIDScan = p.EnumerateRecords;
                        ec.strIDLookup = p.LookupFormStrings;
                        ec.Element = elem;

                        if (elem.repeat > 0)
                        {
                            var ge = new RepeatingElement();
                            c = ge;
                            c.Left = leftOffset;
                            c.Width = maxWidth;
                            c.Top = panelOffset;
                            c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right;

                            ge.InnerControl = ec;
                            ge.Element = elem;
                            ec = ge;
                        }
                        else if (elem.optional > 0)
                        {
                            var re = new OptionalElement();
                            c = re;
                            c.Left = leftOffset;
                            c.Width = maxWidth;
                            c.Top = panelOffset;
                            c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right;

                            re.InnerControl = ec;
                            re.Element = elem;
                            ec = re;
                            c = re;
                        }
                        else
                        {
                            c.Left = leftOffset;
                            c.Width = maxWidth;
                            c.Top = panelOffset;
                            c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right;
                        }

                        this.controlMap.Add(elem, ec);
                        int idx = this.fpanel1.RowCount - 1;
                        this.fpanel1.Controls.Add(c, 0, idx);
                        var info = new RowStyle(SizeType.Absolute, c.Size.Height+2);
                        if (idx == 0)
                            this.fpanel1.RowStyles[0] = info;
                        else
                            this.fpanel1.RowStyles.Add(info);
                        panelOffset = 0;
                        ++this.fpanel1.RowCount;
                    }
                }

                foreach (Element elem in r.EnumerateElements(sr, true))
                {
                    var es = elem.Structure;

                    IElementControl c;
                    if (this.controlMap.TryGetValue(es, out c))
                    {
                        if (c is IGroupedElementControl)
                        {
                            var gc = c as IGroupedElementControl;
                            gc.Elements.Add(elem.Data);
                        }
                        else
                        {
                            c.Data = elem.Data;
                        }
                    }
                }
            }
            catch
            {
                this.strWarnOnSave = "The subrecord doesn't appear to conform to the expected structure.\nThe formatted information may be incorrect.";
                this.Error.SetError(this.bSave, this.strWarnOnSave);
                this.Error.SetIconAlignment(this.bSave, ErrorIconAlignment.MiddleLeft);
                AcceptButton = this.bCancel; // remove save as default button when exception occurs
                CancelButton = this.bCancel;
                UpdateDefaultButton();
            }

            ResumeLayout();
        }
        public void SetContext(Record r, SubRecord sr, bool hexView)
        {
            if (this.r == r && this.sr == sr && this.hexView == hexView)
            {
                return;
            }

            if (r == null || sr == null)
            {
                this.ClearControl();
                return;
            }

            // walk each element in standard fashion
            int panelOffset = 0;
            try
            {
                this.BeginUpdate();

                this.ClearControl();
                SuspendLayout();
                this.fpanel1.SuspendLayout();
                this.fpanel1.Width = Parent.Width;
                this.controlMap.Clear();

                this.hexView = hexView;
                this.r = r;
                this.sr = sr;
                var p = this.GetPluginFromNode(r);
                this.ss = sr.Structure;

                // default to blob if no elements
                if (this.ss == null || this.ss.elements == null || hexView)
                {
                    var c = new HexElement();
                    c.Left = 8;
                    c.Width = this.fpanel1.Width - 16;
                    c.Top = panelOffset;
                    c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right;

                    var elem = r.EnumerateElements(sr, true).FirstOrDefault();
                    if (elem != null)
                    {
                        this.controlMap.Add(elem.Structure, c);
                        this.fpanel1.Controls.Add(c);
                        c.Data = elem.Data;
                    }
                }
                else
                {
                    foreach (var elem in this.ss.elements)
                    {
                        Control c = null;
                        if (elem.options != null && elem.options.Length > 1)
                        {
                            c = new OptionsElement();
                        }
                        else if (elem.flags != null && elem.flags.Length > 1)
                        {
                            c = new FlagsElement();
                        }
                        else
                        {
                            switch (elem.type)
                            {
                                case ElementValueType.LString:
                                    c = new LStringElement();
                                    break;
                                case ElementValueType.FormID:
                                    c = new FormIDElement();
                                    break;
                                case ElementValueType.Blob:
                                    c = new HexElement();
                                    break;
                                default:
                                    c = new TextElement();
                                    break;
                            }
                        }

                        if (c is IElementControl)
                        {
                            var ec = c as IElementControl;
                            ec.formIDLookup = p.GetRecordByID;
                            ec.formIDScan = p.EnumerateRecords;
                            ec.strIDLookup = p.LookupFormStrings;
                            ec.Element = elem;

                            if (elem.repeat > 0)
                            {
                                var ge = new RepeatingElement();
                                c = ge;
                                c.Left = 8;
                                c.Width = this.fpanel1.Width - 16;
                                c.Top = panelOffset;
                                c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right;

                                ge.InnerControl = ec;
                                ge.Element = elem;
                                ec = ge;
                            }
                            else if (elem.optional > 0)
                            {
                                var re = new OptionalElement();
                                c = re;
                                c.Left = 8;
                                c.Width = this.fpanel1.Width - 16;
                                c.Top = panelOffset;
                                c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right;

                                re.InnerControl = ec;
                                re.Element = elem;
                                ec = re;
                                c = re;
                            }
                            else
                            {
                                c.Left = 8;
                                c.Width = this.fpanel1.Width - 16;
                                c.Top = panelOffset;
                                c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right;
                            }

                            c.MinimumSize = c.Size;

                            this.controlMap.Add(elem, ec);
                            this.fpanel1.Controls.Add(c);
                            panelOffset = c.Bottom;
                        }
                    }

                    foreach (Element elem in r.EnumerateElements(sr, true))
                    {
                        var es = elem.Structure;

                        IElementControl c;
                        if (this.controlMap.TryGetValue(es, out c))
                        {
                            if (c is IGroupedElementControl)
                            {
                                var gc = c as IGroupedElementControl;
                                gc.Elements.Add(elem.Data);
                            }
                            else
                            {
                                c.Data = elem.Data;
                            }
                        }
                    }
                }

                Enabled = true;
            }
            catch
            {
                this.strWarnOnSave = "The subrecord doesn't appear to conform to the expected structure.\nThe formatted information may be incorrect.";
            }
            finally
            {
                this.fpanel1.ResumeLayout();
                ResumeLayout();
                this.EndUpdate();
                Refresh();
            }
        }