public string Check()   // calculate if in error, fill Result with what is valid. Empty string if ok
        {
            Result = new ConditionLists();

            string errorlist = "";

            foreach (Group g in groups)
            {
                string innerc = g.innercond.Text;
                string outerc = g.outercond.Text;
                string evt    = (eventlist != null) ? g.evlist.Text : "Default";

                //System.Diagnostics.Debug.WriteLine("Event {0} inner {1} outer {2} action {3} data '{4}'", evt, innerc, outerc, actionname, actiondata );

                Condition fe = new Condition();

                if (evt.Length == 0)        // must have name
                {
                    errorlist += "Ignored group with empty name" + Environment.NewLine;
                }
                else
                {
                    if (fe.Create(evt, "", "", innerc, outerc)) // create must work
                    {
                        for (int i = 0; i < g.condlist.Count; i++)
                        {
                            Group.Conditions c      = g.condlist[i];
                            string           fieldn = c.fname.Text;
                            string           condn  = c.cond.Text;
                            string           valuen = c.value.Text;

                            if (fieldn.Length > 0 || ConditionEntry.IsNullOperation(condn))
                            {
                                ConditionEntry f = new ConditionEntry();

                                if (f.Create(fieldn, condn, valuen))
                                {
                                    if (valuen.Length == 0 && !ConditionEntry.IsUnaryOperation(condn) && !ConditionEntry.IsNullOperation(condn))
                                    {
                                        errorlist += "Do you want filter '" + fieldn + "' in group '" + fe.eventname + "' to have an empty value" + Environment.NewLine;
                                    }

                                    fe.Add(f);
                                }
                                else
                                {
                                    errorlist += "Cannot create filter '" + fieldn + "' in group '" + fe.eventname + "' check value" + Environment.NewLine;
                                }
                            }
                            else
                            {
                                errorlist += "Ignored empty filter " + (i + 1).ToString(System.Globalization.CultureInfo.InvariantCulture) + " in " + fe.eventname + Environment.NewLine;
                            }
                        }

                        if (fe.fields != null)
                        {
                            Result.Add(fe);
                        }
                        else
                        {
                            errorlist += "No valid filters found in group '" + fe.eventname + "'" + Environment.NewLine;
                        }
                    }
                    else
                    {
                        errorlist += "Cannot create " + evt + " not a normal error please report" + Environment.NewLine;
                    }
                }
            }

            return(errorlist);
        }
        private void FixUpGroups(bool calcminsize = true)      // fixes and positions groups.
        {
            SuspendLayout();
            panelVScroll.SuspendLayout();

            int panelwidth = Math.Max(panelVScroll.Width - panelVScroll.ScrollBarWidth, 10);
            int y          = panelymargin;

            for (int i = 0; i < groups.Count; i++)
            {
                Group g = groups[i];
                g.panel.SuspendLayout();

                // for all groups, see if another group below it has the same event selected as ours

                bool showouter = false;

                if (eventlist != null)
                {
                    for (int j = i - 1; j >= 0; j--)
                    {
                        if (groups[j].evlist.Text.Equals(groups[i].evlist.Text) && groups[i].evlist.Text.Length > 0)
                        {
                            showouter = true;
                        }
                    }

                    showouter = showouter && allowoutercond;     // qualify with outer condition switch
                }
                else
                {
                    showouter = (i > 0) && allowoutercond;       // and enabled/disable the outer condition switch
                }
                // Now position the conditions inside the panel

                int vnextcond = panelymargin;

                int condxoffset = (g.evlist != null) ? (g.evlist.Right + 8) : panelxmargin;
                int farx        = condxoffset; // should never not have a condition but ..

                int panelxspacing = Font.ScalePixels(4);
                int panelyspacing = Font.ScalePixels(6);

                for (int condc = 0; condc < g.condlist.Count; condc++)
                {
                    Group.Conditions c = g.condlist[condc];
                    c.fname.Location = new Point(condxoffset, vnextcond);
                    c.fname.Enabled  = !ConditionEntry.IsNullOperation(c.cond.Text);
                    if (!c.fname.Enabled)
                    {
                        c.fname.Text = "";
                    }

                    c.cond.Location = new Point(c.fname.Right + panelxspacing, vnextcond);

                    c.value.Location = new Point(c.cond.Right + panelxspacing, vnextcond);
                    c.value.Width    = panelwidth - condxoffset - c.fname.Width - 4 - c.cond.Width - 4 - c.del.Width - 4 - c.more.Width - 4 - g.innercond.Width - 4 - g.upbutton.Width + 8;
                    c.value.Enabled  = !ConditionEntry.IsNullOperation(c.cond.Text) && !ConditionEntry.IsUnaryOperation(c.cond.Text);
                    if (!c.value.Enabled)
                    {
                        c.value.Text = "";
                    }

                    c.del.Location  = new Point(c.value.Right + panelxspacing, vnextcond);
                    c.more.Location = new Point(c.del.Right + panelxspacing, vnextcond);
                    c.more.Visible  = (condc == g.condlist.Count - 1);

                    vnextcond += c.fname.Height + panelyspacing;
                    farx       = c.more.Left; // where the innercond/up buttons are
                }

                // and the outer/inner conditions

                g.innercond.Visible  = (g.condlist.Count > 1);        // inner condition on if multiple
                g.innercond.Location = new Point(farx, panelymargin); // inner condition is in same place as more button
                farx = g.innercond.Right + panelxspacing;             // move off

                // and the up button..
                g.upbutton.Visible  = (i != 0 && g.condlist.Count > 0);
                g.upbutton.Location = new Point(farx, panelymargin);

                // allocate space for the outercond if req.
                g.outercond.Enabled = g.outercond.Visible = g.outerlabel.Visible = showouter;       // and enabled/disable the outer condition switch

                if (showouter)
                {
                    g.outercond.Location  = new Point(panelxmargin, vnextcond);
                    g.outerlabel.Location = new Point(g.outercond.Location.X + g.outercond.Width + panelxspacing, g.outercond.Location.Y + 3);
                    vnextcond            += g.outercond.Height + panelyspacing;
                }

                // pos the panel

                g.panel.Location    = new Point(panelxmargin, y + panelVScroll.ScrollOffset);
                g.panel.Size        = new Size(Math.Max(panelwidth - panelxmargin * 2, farx), Math.Max(vnextcond + panelyspacing, g.innercond.Bottom + panelyspacing));
                g.panel.BorderStyle = (g.condlist.Count > 1) ? BorderStyle.FixedSingle : BorderStyle.None;

                y += g.panel.Height + panelyspacing * 2;

                // and make sure actions list is right

                g.panel.ResumeLayout();
            }

            if (allowoutercond || groups.Count == 0)
            {
                buttonMore.Location = new Point(panelxmargin, y + panelVScroll.ScrollOffset);
                buttonMore.Visible  = true;
                y = buttonMore.Bottom;
            }
            else
            {
                buttonMore.Visible = false;
            }

            if (calcminsize)
            {
                onCalcMinsize?.Invoke(y);
            }

            panelVScroll.ResumeLayout();
            ResumeLayout();
            Invalidate(true);
            Update();
        }