コード例 #1
0
ファイル: Share.cs プロジェクト: HJfod/gdtools
            public Share()
            {
                this.Name = "Sharing";
                this.Dock = DockStyle.Fill;
                Meth.HandleTheme(this);

                ImportLeveLArea          = new FlowLayoutPanel();
                ImportLeveLArea.Dock     = DockStyle.Fill;
                ImportLeveLArea.AutoSize = true;

                ExportSelect              = new Elem.Select();
                ExportSelect.DoubleClick += (s, e) => ViewInfo();

                foreach (dynamic lvl in GDTools.GetLevelList(null, null, true))
                {
                    ExportSelect.AddItem(lvl.Name);
                }

                ExportCompressed          = new CheckBox();
                ExportCompressed.Text     = "Export compressed (.gmdc)";
                ExportCompressed.AutoSize = true;

                RefreshDiv          = new TableLayoutPanel();
                RefreshDiv.AutoSize = true;
                RefreshDiv.Visible  = false;

                RefreshDiv.Controls.Add(new Elem.Text("After importing all you want, make sure to refresh data in order to use the app further."));
                RefreshDiv.Controls.Add(new Elem.But("Refresh", (s, e) => Program.MainForm.FullReload()));

                FlowLayoutPanel ExportControls = new FlowLayoutPanel();

                ExportControls.AutoSize = true;

                ExportControls.Controls.Add(new Elem.But("Export", (s, e) => ExportLevel(), "Exports all the level(s) you've selected on the list"));
                ExportControls.Controls.Add(new Elem.But("View", (s, e) => ViewInfo(), "Shows info for the topmost level you've selected on the list."));

                this.Controls.Add(ExportSelect);
                this.Controls.Add(ExportControls);
                this.Controls.Add(ExportCompressed);
                this.Controls.Add(new Elem.NewLine());
                this.Controls.Add(new Elem.But("Help", (s, e) => Pages.SettingPage.ShowHelp("share")));
                this.Controls.Add(new Elem.SectionBreak());
                this.Controls.Add(new Elem.NewLine());
                this.Controls.Add(new Elem.But("Import", (s, e) => OpenImport(), "Opens a file browsing dialog where you can select level(s) to add to imports."));
                this.Controls.Add(RefreshDiv);
                this.Controls.Add(ImportLeveLArea);
            }
コード例 #2
0
ファイル: Collab.cs プロジェクト: HJfod/gdtools
            public Collabs()
            {
                this.Name = "Collab";
                this.Dock = DockStyle.Fill;
                Meth.HandleTheme(this);

                TableLayoutPanel con = new TableLayoutPanel();

                con.AutoSize = true;
                con.Visible  = Settings.DevMode;

                MergeList = new Elem.Select(false);
                MergeBase = new Elem.Text("Base not selected");

                FlowLayoutPanel MergeControls = new FlowLayoutPanel();

                MergeControls.AutoSize = true;

                MergeControls.Controls.Add(new Elem.But("Set base", (s, e) => {
                    Elem.ChooseForm Select = new Elem.ChooseForm("Select base source",
                                                                 new string[] { "Set base from file", "Set base from local levels", "Set base by ID" });

                    Select.Show();

                    Select.Finish += res => {
                        if (res == 0)
                        {
                            using (OpenFileDialog ofd = new OpenFileDialog()) {
                                ofd.InitialDirectory = "c:\\";
                                ofd.Filter           = GDTools.Ext.Filter;
                                ofd.FilterIndex      = 1;
                                ofd.RestoreDirectory = true;
                                ofd.Multiselect      = true;

                                if (ofd.ShowDialog() == DialogResult.OK)
                                {
                                    foreach (string file in ofd.FileNames)
                                    {
                                        Elem.MsgBox LoadInfo = new Elem.MsgBox("Loading...");
                                        LoadInfo.Show();
                                        AddBase(file);
                                        LoadInfo.Close();
                                        LoadInfo.Dispose();
                                    }
                                }
                            }
                        }
                        else if (res == 1)
                        {
                            Form Choose = new Form();
                            Choose.Text = "Double-click to select";
                            Choose.Size = new Size(400, 300);
                            Meth.HandleTheme(Choose);

                            Elem.Select ExportSelect = new Elem.Select(false);

                            EventHandler Pick = (s, e) => {
                                if (ExportSelect.SelectedItem == null)
                                {
                                    return;
                                }
                                AddBase(((Elem.Select.SelectItem)ExportSelect.SelectedItem).Text);
                                Choose.Close();
                                Choose.Dispose();
                            };

                            ExportSelect.DoubleClick += Pick;

                            foreach (dynamic lvl in GDTools.GetLevelList())
                            {
                                ExportSelect.AddItem(lvl.Name);
                            }

                            Choose.Controls.Add(ExportSelect);

                            Choose.Show();
                        }
                        else if (res == 2)
                        {
                            Elem.ChooseForm c = new Elem.ChooseForm("Type Level ID",
                                                                    new string[] { "IS-INPUT::INT", "::Add", "Cancel" },
                                                                    "Type in level ID"
                                                                    );

                            c.Show();

                            c.FinishStr += resc => {
                                if (resc != "")
                                {
                                    Elem.MsgBox LoadInfo = new Elem.MsgBox("Loading...");
                                    LoadInfo.Show();

                                    string r = GDTools.RequestGDLevel(resc);

                                    if (r.StartsWith("-"))
                                    {
                                        MessageBox.Show($"Error: {GDTools.VerifyRequest(r)}", "Could not get level!");
                                    }

                                    AddBase($"{resc} ({GDTools.GetRequestKey(r, "2")})");

                                    LoadInfo.Dispose();
                                }
                            };
                        }
                    };
                }));
                MergeControls.Controls.Add(new Elem.But("Add part(s)", (s, e) => {
                    Elem.ChooseForm Select = new Elem.ChooseForm("Select part source",
                                                                 new string[] { "Add part(s) from file", "Add part(s) from local levels", "Add part(s) by ID" });

                    Select.Show();

                    Select.Finish += res => {
                        if (res == 0)
                        {
                            using (OpenFileDialog ofd = new OpenFileDialog()) {
                                ofd.InitialDirectory = "c:\\";
                                ofd.Filter           = GDTools.Ext.Filter;
                                ofd.FilterIndex      = 1;
                                ofd.RestoreDirectory = true;
                                ofd.Multiselect      = true;

                                if (ofd.ShowDialog() == DialogResult.OK)
                                {
                                    foreach (string file in ofd.FileNames)
                                    {
                                        Elem.MsgBox LoadInfo = new Elem.MsgBox("Loading...");
                                        LoadInfo.Show();
                                        AddMerge(file);
                                        LoadInfo.Close();
                                        LoadInfo.Dispose();
                                    }
                                }
                            }
                        }
                        else if (res == 1)
                        {
                            Form Choose = new Form();
                            Choose.Text = "Double-click to select";
                            Choose.Size = new Size(400, 300);
                            Meth.HandleTheme(Choose);

                            Elem.Select ExportSelect = new Elem.Select();

                            EventHandler Pick = (s, e) => {
                                if (ExportSelect.SelectedItems[0] == null)
                                {
                                    return;
                                }
                                foreach (Elem.Select.SelectItem x in ExportSelect.SelectedItems)
                                {
                                    AddMerge(x.Text);
                                }
                                Choose.Close();
                                Choose.Dispose();
                            };

                            ExportSelect.DoubleClick += Pick;

                            foreach (dynamic lvl in GDTools.GetLevelList())
                            {
                                ExportSelect.AddItem(lvl.Name);
                            }

                            Choose.Controls.Add(new Elem.Div(new Control[] {
                                ExportSelect,
                                new Elem.But("Select", Pick)
                            }));

                            Choose.ShowDialog(Select);
                        }
                        else if (res == 2)
                        {
                            Elem.ChooseForm c = new Elem.ChooseForm("Type Level ID(s)",
                                                                    new string[] { "IS-INPUT-BIG::INS", "::Add", "Cancel" },
                                                                    "Type in level ID(s) (Separated by spaces)"
                                                                    );

                            c.Show();

                            c.FinishStr += resc => {
                                if (resc != "")
                                {
                                    int i          = 0;
                                    string[] rescs = resc.Split(" ");
                                    foreach (string ress in rescs)
                                    {
                                        i++;
                                        Elem.MsgBox LoadInfo = new Elem.MsgBox($"Loading ({i}/{rescs.Length})...");
                                        LoadInfo.Show();

                                        if (ress.Length < 3)
                                        {
                                            LoadInfo.Dispose();
                                            continue;
                                        }

                                        string r = GDTools.RequestGDLevel(ress);

                                        if (r.StartsWith("-"))
                                        {
                                            MessageBox.Show($"Error with {ress}: {GDTools.VerifyRequest(r)}", "Could not get level!");
                                            LoadInfo.Dispose();
                                            continue;
                                        }

                                        AddMerge($"{ress} ({GDTools.GetRequestKey(r, "2")})");

                                        LoadInfo.Dispose();
                                    }
                                }
                            };
                        }
                    };
                }));
                MergeControls.Controls.Add(new Elem.But("Remove part", (s, e) => {
                    if (MergeList.SelectedItem == null)
                    {
                        return;
                    }
                    MergeList.Items.Remove(MergeList.SelectedItem);
                }));
                MergeControls.Controls.Add(new Elem.But("Merge", (s, e) => {
                    string err = MergeParts();
                    if (err.Length > 0)
                    {
                        MessageBox.Show(err, "Error merging");
                    }
                }));

                CheckBox UseReferenceToggle = new CheckBox();

                UseReferenceToggle.Text     = "Use reference objects";
                UseReferenceToggle.AutoSize = true;
                UseReferenceToggle.Checked  = UseReferenceObjects;
                UseReferenceToggle.Click   += (s, e) =>
                                              UseReferenceObjects = UseReferenceToggle.Checked;

                CheckBox MergeLinkToggle = new CheckBox();

                MergeLinkToggle.Text                           = "Link part objects";
                MergeLinkToggle.AutoSize                       = true;
                MergeLinkToggle.Click                         += (s, e) =>
                                                     MergeLink = MergeLinkToggle.Checked;

                CheckBox AutoReassignToggle = new CheckBox();

                AutoReassignToggle.Text     = "Reassign groups and colours";
                AutoReassignToggle.AutoSize = true;
                AutoReassignToggle.Checked  = AutoReassignGroups;
                AutoReassignToggle.Click   += (s, e) =>
                                              AutoReassignGroups = AutoReassignToggle.Checked;

                con.Controls.Add(new Elem.Text("Part merging"));
                con.Controls.Add(MergeList);
                con.Controls.Add(MergeBase);
                con.Controls.Add(MergeControls);
                con.Controls.Add(MergeLinkToggle);
                con.Controls.Add(AutoReassignToggle);
                con.Controls.Add(UseReferenceToggle);

                this.Controls.Add(con);
                if (!Settings.DevMode)
                {
                    this.Controls.Add(new Elem.DevToolWarning((s, e) => { con.Visible = true; }));
                }
            }
コード例 #3
0
            public LevelEdit() {
                this.Name = "Level";
                this.Dock = DockStyle.Fill;
                Meth.HandleTheme(this);

                this.SelectPanel = new TableLayoutPanel();
                this.SelectPanel.AutoSize = true;

                this.SelectLevel = new Elem.Select(false);
                this.SelectLevel.DoubleClick += (s, e) => this.SelectLevelToEdit();

                foreach (dynamic lvl in GDTools.GetLevelList(null, null, true))
                    this.SelectLevel.AddItem(lvl.Name);
                
                this.SelectPanel.Controls.Add(SelectLevel);
                this.SelectPanel.Controls.Add(new Elem.But("Select", (s, e) => this.SelectLevelToEdit(), "Select a level to edit"));



                this.EditPanel = new TableLayoutPanel();
                this.EditPanel.Visible = false;
                this.EditPanel.AutoSize = true;

                this.EditPanel.Controls.Add(new Elem.But("⟵", (s, e) => {
                    this.SelectedLevelContent = new {};
                    this.SelectPanel.Visible = true;
                    this.EditPanel.Visible = false;
                }));

                this.EditPanel.Controls.Add(new Elem.NewLine());

                this.LevelName = new Elem.Text();
                this.EditPanel.Controls.Add(LevelName);
                this.EditPanel.Controls.Add(new Elem.BigNewLine());

                CheckBox ExportCompressed = new CheckBox();
                ExportCompressed.Text = "Export compressed (.gmdc)";
                ExportCompressed.AutoSize = true;

                this.EditPanel.Controls.Add(new Elem.But("Create guidelines from BPM", (s, e) => {
                    Form c = new Form();
                    c.Text = "Enter BPM";
                    Meth.HandleTheme(c);
                    
                    TableLayoutPanel con = new TableLayoutPanel();
                    con.AutoSize = true;

                    con.Controls.Add(new Elem.Input("__i_BPM", "INT", "BPM"));
                    con.Controls.Add(new Elem.Input("__i_OFFSET", "INT", "Offset (ms)"));
                    con.Controls.Add(new Elem.Input("__i_TIMESIG", "INT", "Time signature (x/4)"));
                    con.Controls.Add(new Elem.Input("__i_LENGTH", "INT", "Length (s)"));
                    
                    CheckBox KeepOldGuidelines = new CheckBox();
                    KeepOldGuidelines.Text = "Keep old guidelines";
                    KeepOldGuidelines.AutoSize = true;
                    KeepOldGuidelines.Checked = true;

                    con.Controls.Add(KeepOldGuidelines);

                    con.Controls.Add(new Elem.Div(new Control[] {
                        new Elem.But("Create", (s, e) => {
                            string iBPM = con.Controls.Find("__i_BPM", false)[0].Text;
                            string iOFF = con.Controls.Find("__i_OFFSET", false)[0].Text;
                            string iSIG = con.Controls.Find("__i_TIMESIG", false)[0].Text;
                            string iLGT = con.Controls.Find("__i_LENGTH", false)[0].Text;

                            if (iBPM.Length == 0 || iOFF.Length == 0 || iSIG.Length == 0 || iLGT.Length == 0) return;

                            float BPMmultiplier = 60F / Int32.Parse(iBPM);

                            int LineCount = Int32.Parse(iLGT) * Int16.Parse(iSIG);
                            int TimeSignature = Int16.Parse(iSIG);
                            float offset = Int32.Parse(iOFF) / 1000F;
                            string bpmData = "";

                            for (int i = 0; i < LineCount; i++)
                                bpmData += $"{Math.Round((float)i * BPMmultiplier + offset, 2)}~{(i % TimeSignature == 0 ? "1" : "0")}~";

                            string ndat = this.SelectedLevelContent.Data;
                            string dat = this.SelectedLevelContent.k4;

                            if (KeepOldGuidelines.Checked)
                                bpmData += $"{GDTools.GetStartKey(dat, "kA14")}~";

                            ndat = GDTools.SetKey(ndat, "k4", GDTools.SetStartKey(dat, "kA14", bpmData.Substring(0, bpmData.Length - 1)));

                            GDTools.UpdateLevel(ndat);

                            c.Dispose();

                            Program.MainForm.FullReload();
                        }),
                        new Elem.But("Cancel", (s, e) => c.Dispose())
                    }));

                    c.Controls.Add(con);

                    c.Show();
                }, "Used to generate automatic guidelines in the level out of the song's BPM to ease syncing."));

                this.EditPanel.Controls.Add(new Elem.But("Edit level properties", (s, e) => {
                    Elem.BasicForm c = new Elem.BasicForm();
                    c.Text = "Edit level properties";
                    c.Size = new Size(Meth._S(350),Meth._S(350));

                    string newData = this.SelectedLevelContent.Data;
                    
                    TableLayoutPanel con = new TableLayoutPanel();
                    con.AutoSize = true;

                    con.ColumnCount = 3;
                    con.RowCount = 6;

                    con.Controls.Add(new Elem.Text("Name: "), 0, 0);
                    con.Controls.Add(new Elem.Input("__L_NAME", "ANY", "", GDTools.GetKey(newData, "k2"), true), 1, 0);

                    con.Controls.Add(new Elem.Text("Creator: "), 0, 1);
                    con.Controls.Add(new Elem.Input("__L_CREATOR", "ANY", "", GDTools.GetKey(newData, "k5"), true), 1, 1);

                    con.Controls.Add(new Elem.Text("Password: "******"__L_PASSWORD", "INT", "", GDTools.GetKey(newData, "k41"), true), 1, 2);

                    string desc = GDTools.GetKey(newData, "k3");
                    try { desc = Encoding.UTF8.GetString(GDTools.DecryptBase64(desc)); } catch (Exception) {};

                    con.Controls.Add(new Elem.Text("Description: "), 0, 3);
                    con.Controls.Add(new Elem.Input("__L_DESC", "ANY", "", desc, true), 1, 3);

                    con.Controls.Add(new Elem.Text(""), 0, 4);

                    con.Controls.Add(new Elem.But("Apply changes", (s, e) => {
                        newData = GDTools.SetKey(newData, "k2",     con.Controls.Find("__L_NAME", true)[0].Text);
                        newData = GDTools.SetKey(newData, "k5",     con.Controls.Find("__L_CREATOR", true)[0].Text);
                        newData = GDTools.SetKey(newData, "k41",    con.Controls.Find("__L_PASSWORD", true)[0].Text);
                        newData = GDTools.SetKey(newData, "k3",     GDTools.EncryptBase64(Encoding.UTF8.GetBytes(con.Controls.Find("__L_DESC", true)[0].Text)));

                        GDTools.UpdateLevel(newData.Replace(System.Environment.NewLine, ""));

                        c.Dispose();

                        Program.MainForm.FullReload();
                    }), 0, 5);

                    c.Controls.Add(con);

                    c.Show();
                }, "Edit level properties such as name, description, etc. (Hint: You can add newlines to descriptions!)"));

                this.EditPanel.Controls.Add(new Elem.But("View level info", (s, e) => {
                    dynamic LevelInfo = GDTools.GetLevelInfo(this.SelectedLevel);
                        
                    string Info = "";

                    foreach (PropertyInfo i in LevelInfo.GetType().GetProperties()) 
                        Info += $"{i.Name.Replace("_", " ")}: {i.GetValue(LevelInfo)}\n";

                    MessageBox.Show(Info, $"Info for {this.SelectedLevel}", MessageBoxButtons.OK, MessageBoxIcon.None);
                }, "View info about the selected level."));

                this.EditPanel.Controls.Add(new Elem.But("Generate T4 glow", (s, e) => {
                    Elem.BasicForm c = new Elem.BasicForm();
                    c.Text = "Generate T4 glow";
                    c.Size = new Size(Meth._S(350),Meth._S(350));

                    string newData = this.SelectedLevelContent.Data;
                    
                    TableLayoutPanel con = new TableLayoutPanel();
                    con.AutoSize = true;

                    con.ColumnCount = 3;
                    con.RowCount = 7;

                    con.Controls.Add(new Elem.Text("X position: "), 0, 0);
                    con.Controls.Add(new Elem.Input("__L_X", "INT", "", "0"), 1, 0);

                    con.Controls.Add(new Elem.Text("Y position: "), 0, 1);
                    con.Controls.Add(new Elem.Input("__L_Y", "INT", "", "0"), 1, 1);

                    con.Controls.Add(new Elem.Text("Scale: "), 0, 2);
                    con.Controls.Add(new Elem.Input("__L_S", "FLT", "", "1"), 1, 2);

                    con.Controls.Add(new Elem.Text(""), 0, 4);

                    con.Controls.Add(new Elem.But("Generate", (s, e) => {
                        string obj = GDTools.DecodeLevelData(GDTools.GetKey(newData, "k4"));

                        obj += $"1,1888,2,{con.Controls.Find("__L_X", true)[0].Text},3,{con.Controls.Find("__L_Y", true)[0].Text},24,10,32,{con.Controls.Find("__L_S", true)[0].Text};";

                        newData = GDTools.SetKey(newData, "k4", GDTools.EncodeLevelData(obj));

                        GDTools.UpdateLevel(newData);

                        c.Dispose();

                        Program.MainForm.FullReload();
                    }), 0, 5);

                    con.Controls.Add(new Elem.Text("T4 glow is Blending glow that can be put above T3 solid objects.\r\n\r\nYou have to give the glow a color that has Blending enabled.", new Size(150, 0)), 0, 6);

                    c.Controls.Add(con);

                    c.Show();
                }, "Generates a piece of T4 glow at the start of the level."));

                this.EditPanel.Controls.Add(new Elem.But("Edit level data", (s, e) => {
                    Elem.BasicForm DataEditor = new Elem.BasicForm();
                    DataEditor.Size = new Size(800, 600);

                    int ControlsHeight = 50;

                    TableLayoutPanel DataEditorMain = new TableLayoutPanel();
                    DataEditorMain.AutoSize = true;
                    DataEditorMain.Dock = DockStyle.Fill;

                    TableLayoutPanel DataEditorEditor = new TableLayoutPanel();
                    DataEditorEditor.ColumnCount = 2;
                    DataEditorEditor.Dock = DockStyle.Fill;
                    DataEditorEditor.AutoScroll = true;
                    DataEditorEditor.Size = new Size(DataEditor.Size.Width - 30, DataEditor.Size.Height - ControlsHeight - 100);

                    FlowLayoutPanel DataEditorControls = new FlowLayoutPanel();
                    DataEditorControls.AutoSize = true;
                    DataEditorControls.Dock = DockStyle.Bottom;
                    DataEditorControls.Height = ControlsHeight;

                    string[] objs = this.SelectedLevelContent.k4.Split(";");
                    int page = 0;
                    int show = 20;

                    Elem.Text PageNum = new Elem.Text();
                    Elem.Text PageAmt = new Elem.Text();

                    void PageUpdate() {
                        DataEditorEditor.Controls.Clear(true);

                        PageNum.Text = $"Page: {page / show + 1} / {objs.Length / show + 1}";
                        PageAmt.Text = $"Amount of object(s) shown on page: {show}";
                        
                        int i = 0;
                        foreach (string obj in objs.Red(page, show)) {
                            if (obj == null) continue;
                            DataEditorEditor.Controls.Add(new Elem.Text($"{page + i}:"), 0, i);
                            DataEditorEditor.Controls.Add(new Elem.Text($"{obj}"), 1, i);

                            i++;
                        }
                    };

                    PageUpdate();

                    DataEditorControls.Controls.Add(PageNum);
                    DataEditorControls.Controls.Add(PageAmt);
                    DataEditorControls.Controls.Add(new Elem.But("Next", (s, e) => {
                        if (page < objs.Length) { page += show; PageUpdate(); };
                    }));
                    DataEditorControls.Controls.Add(new Elem.But("Previous", (s, e) => {
                        if (page > 0) { page -= show; PageUpdate(); };
                    }));
                    DataEditorControls.Controls.Add(new Elem.But("Go to page", (s, e) => {
                        Elem.ChooseForm c = new Elem.ChooseForm( "Go to page", 
                            new string[] { "IS-INPUT::INT", "::Go", "Cancel" }
                        );

                        c.Show();

                        c.FinishStr += resc => {
                            if (resc != "") {
                                int np = Int32.Parse(resc) - 1;
                                if (np >= 0 && np <= objs.Length / show)
                                    page = np * show;

                                PageUpdate();
                                c.Dispose();
                            }
                        };
                    }));

                    DataEditorMain.Controls.Add(DataEditorEditor);
                    DataEditorMain.Controls.Add(DataEditorControls);
                    DataEditor.Controls.Add(DataEditorMain);

                    DataEditor.Show();
                }));

                this.EditPanel.Controls.Add(new Elem.But("Rearrange Groups And Colours", (s, e) => {
                    Elem.BasicForm c = new Elem.BasicForm();
                    c.Text = "Rearrange Groups And Colours";
                    c.Size = new Size(Meth._S(350),Meth._S(250));

                    string newData = this.SelectedLevelContent.k4;
                    
                    TableLayoutPanel con = new TableLayoutPanel();
                    con.AutoSize = true;

                    con.ColumnCount = 3;
                    con.RowCount = 7;

                    con.Controls.Add(new Elem.Text("Group Range"), 0, 0);
                    con.Controls.Add(new Elem.Input("__G_RANGE", "ANY", "", "x - y", false, false), 0, 1);

                    con.Controls.Add(new Elem.Text("Offset"), 1, 0);
                    con.Controls.Add(new Elem.Input("__G_OFF", "INN", "", "+0", false, false), 1, 1);

                    con.Controls.Add(new Elem.Text(""), 0, 2);

                    con.Controls.Add(new Elem.Text("Color Range"), 0, 3);
                    con.Controls.Add(new Elem.Input("__C_RANGE", "ANY", "", "x - y", false, false), 0, 4);

                    con.Controls.Add(new Elem.Text("Offset"), 1, 3);
                    con.Controls.Add(new Elem.Input("__C_OFF", "INN", "", "+0", false, false), 1, 4);

                    con.Controls.Add(new Elem.Text(""), 0, 5);

                    con.Controls.Add(new Elem.But("Apply changes", (s, e) => {
                        try {
                            string grang = con.Controls.Find("__G_RANGE", true)[0].Text.Trim();
                            if (!Regex.IsMatch(grang, @"\d+\s*\-\s*\d+")) throw new Exception("Invalid input in group range!");

                            string goff = con.Controls.Find("__G_OFF", true)[0].Text.Trim();
                            if (!Regex.IsMatch(goff, @"[+|-]?\s*\d+")) throw new Exception("Invalid input in group offset!");

                            string crang = con.Controls.Find("__C_RANGE", true)[0].Text.Trim();
                            if (!Regex.IsMatch(crang, @"\d+\s*\-\s*\d+")) throw new Exception("Invalid input in color range!");

                            string coff = con.Controls.Find("__C_OFF", true)[0].Text.Trim();
                            if (!Regex.IsMatch(coff, @"[+|-]?\s*\d+")) throw new Exception("Invalid input in color offset!");

                            // groups are separated like a.b.c.d.e
                            // colors are just the color id

                            // things you need to affect: color triggers, pulse triggers, literally every trigger that takes groups

                            string new_data = "";
                            foreach (dynamic obj in GDTools.GetObjectsByKey(newData))
                                if (GDTools.GetObjectKey(obj.Data, "57") != null) {
                                    int o = Int32.Parse(GDTools.GetObjectKey(obj.Data, "57"));
                                    string n = obj.Data;
                                    if (Int32.Parse(grang.Split("-")[0] < o && o < Int32.Parse(grang.Split("-")[1]))
                                        n = GDTools.SetObjectKey(obj.Data, "57", (o + Int32.Parse(goff)).ToString());
                                    new_data += n + ";";
                                } else new_data += obj.Data + ";";
                        } catch (Exception err) {
                            MessageBox.Show($"Error: {err}", "Error");
                        }
                    }), 0, 6);

                    con.Controls.Add(new Elem.But("Cancel", (s, e) => c.Dispose()), 1, 6);

                    c.Controls.Add(con);

                    c.Show();
                }));