From 8cee209f3b3d41fd9682601b12360f05a2dd931e Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Thu, 1 Aug 2019 01:22:46 -0400 Subject: [PATCH] Slowly but surely making progress toward better user interface --- .../Controls/GenericBrowserButton.cs | 158 ++++++++++ .../UniversalEditorFileBrowserControl.cs | 151 +++++++++ .../Dialogs/DocumentPropertiesDialogV2.cs | 298 ++++++++++++++++++ .../MainWindow.cs | 13 + .../UniversalEditor.UserInterface.csproj | 4 + 5 files changed, 624 insertions(+) create mode 100644 CSharp/Libraries/UniversalEditor.UserInterface/Controls/GenericBrowserButton.cs create mode 100644 CSharp/Libraries/UniversalEditor.UserInterface/Controls/UniversalEditorFileBrowserControl.cs create mode 100644 CSharp/Libraries/UniversalEditor.UserInterface/Dialogs/DocumentPropertiesDialogV2.cs diff --git a/CSharp/Libraries/UniversalEditor.UserInterface/Controls/GenericBrowserButton.cs b/CSharp/Libraries/UniversalEditor.UserInterface/Controls/GenericBrowserButton.cs new file mode 100644 index 00000000..69e14825 --- /dev/null +++ b/CSharp/Libraries/UniversalEditor.UserInterface/Controls/GenericBrowserButton.cs @@ -0,0 +1,158 @@ +// +// GenericBrowserButton.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using UniversalWidgetToolkit.Controls; +using UniversalWidgetToolkit.Input.Keyboard; +using UniversalWidgetToolkit; +using UniversalWidgetToolkit.Layouts; +using System.Collections.ObjectModel; +using System.Collections.Generic; + +namespace UniversalEditor.UserInterface.Controls +{ + public class GenericBrowserButton : DropDownButton + where TObj : class, References + where TRef : class, ReferencedBy + { + public GenericBrowserButton () + { + initct (); + } + + public event EventHandler SelectionChanged; + + private ListView lv = null; + private DefaultTreeModel tm = null; + public Collection AvailableObjects { get; } = new Collection(); + public TObj SelectedObject { get; set; } = default(TObj); + + private TextBox txtSearch = null; + + private void initct() + { + Container ctObjectModel = new Container (); + ctObjectModel.Layout = new BoxLayout (Orientation.Vertical); + ctObjectModel.MinimumSize = new MBS.Framework.Drawing.Dimension2D (300, 200); + + txtSearch = new TextBox (); + txtSearch.Changed += txtSearch_Changed; + txtSearch.KeyDown += txtSearch_KeyDown; + ctObjectModel.Controls.Add (txtSearch, new BoxLayout.Constraints (false, true)); + + tm = new DefaultTreeModel (new Type[] { typeof(string), typeof(string) }); + + lv = new ListView (); + lv.Model = tm; + lv.Columns.Add (new ListViewColumnText (lv.Model.Columns [0], "Name")); + lv.Columns.Add (new ListViewColumnText (lv.Model.Columns [1], "Description")); + lv.HeaderStyle = ColumnHeaderStyle.None; + ctObjectModel.Controls.Add (lv, new BoxLayout.Constraints (true, true)); + + this.Container = ctObjectModel; + } + + protected override void OnCreated (EventArgs e) + { + base.OnCreated (e); + UpdateSearch (); + } + + private void txtSearch_Changed(object sender, EventArgs e) + { + UpdateSearch(); + } + + private void UpdateSearch() + { + tm.Rows.Clear(); + foreach (TRef item in AvailableObjects) + { + bool itemShouldFilter = false; + string[] details = item.GetDetails(); + foreach (string detail in details) + { + if (detail == null) continue; + if (detail.ToLower().Trim().Contains(txtSearch.Text.ToLower().Trim())) + { + itemShouldFilter = true; + break; + } + } + if (String.IsNullOrEmpty(txtSearch.Text.Trim()) || itemShouldFilter) + { + AddObjectToList(item); + } + } + + if (tm.Rows.Count == 1) + { + // lv.Items[0].Selected = true; + } + // lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); + } + + private void AddObjectToList(TRef itmr) + { + string[] details = itmr.GetDetails(); + List columns = new List(); + + for (int i = 0; i < details.Length; i++) + { + string str = details[i]; + if (String.IsNullOrEmpty(str)) str = String.Empty; + + columns.Add(new TreeModelRowColumn(tm.Columns[i], str)); + } + + TreeModelRow lvi = new TreeModelRow(columns.ToArray()); + lvi.SetExtraData("TRef", itmr); + tm.Rows.Add(lvi); + } + + private void lv_RowActivated(object sender, ListViewRowActivatedEventArgs e) + { + // if (lv.SelectedItems.Count != 1) return; + + SelectedObject = e.Row.GetExtraData("TRef")?.Create(); + SelectionChanged?.Invoke(this, e); + CloseDropDown(); + } + + private void txtSearch_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyData == KeyboardKey.Enter) + { + if (lv.SelectedRows.Count != 1) return; + + SelectedObject = lv.SelectedRows[0].GetExtraData("TRef")?.Create(); + if (SelectionChanged != null) SelectionChanged(this, e); + + CloseDropDown(); + } + else if (e.KeyData == KeyboardKey.Escape) + { + // already handled by GTK? but what about other platforms + // Close(); + } + } + } +} + diff --git a/CSharp/Libraries/UniversalEditor.UserInterface/Controls/UniversalEditorFileBrowserControl.cs b/CSharp/Libraries/UniversalEditor.UserInterface/Controls/UniversalEditorFileBrowserControl.cs new file mode 100644 index 00000000..6173942f --- /dev/null +++ b/CSharp/Libraries/UniversalEditor.UserInterface/Controls/UniversalEditorFileBrowserControl.cs @@ -0,0 +1,151 @@ +// +// UniversalEditorFileBrowserControl.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using UniversalWidgetToolkit; +using UniversalWidgetToolkit.Layouts; +using UniversalWidgetToolkit.Controls.FileBrowser; +using UniversalWidgetToolkit.Controls; +using System.Collections.Generic; + +namespace UniversalEditor.UserInterface.Controls +{ + public class UniversalEditorFileBrowserControl : Container + { + private FileBrowserControl _Browser = null; + private Container _Table = null; + + private GenericBrowserButton cboObjectModel = null; + private GenericBrowserButton cboDataFormat = null; + + public FileBrowserMode Mode { get { return _Browser.Mode; } set { _Browser.Mode = value; } } + + public ObjectModel ObjectModel { get; set; } = null; + public DataFormat DataFormat { get; set; } = null; + + public UniversalEditorFileBrowserControl () + { + this.Layout = new BoxLayout (Orientation.Vertical); + + _Browser = new FileBrowserControl (); + this.Controls.Add (_Browser, new BoxLayout.Constraints (true, true)); + + cboObjectModel = new GenericBrowserButton (); + // cboObjectModel.SelectedObject = ObjectModel; + + cboObjectModel.Text = "Object _model: (not selected)"; + + ObjectModelReference[] omrs = new ObjectModelReference[0]; + + if (Mode == FileBrowserMode.Save) + { + // show all dataformats for the current object model + if (DataFormat == null) + { + omrs = UniversalEditor.Common.Reflection.GetAvailableObjectModels(); + } + else + { + omrs = UniversalEditor.Common.Reflection.GetAvailableObjectModels(DataFormat.MakeReference()); + } + } + else if (Mode == FileBrowserMode.Open) + { + /* + if (Accessor != null) + { + // show all dataformats for the current accessor + omrs = UniversalEditor.Common.Reflection.GetAvailableObjectModels(Accessor); + } + else*/ + { + omrs = UniversalEditor.Common.Reflection.GetAvailableObjectModels(); + } + } + foreach (ObjectModelReference omr in omrs) + { + cboObjectModel.AvailableObjects.Add(omr); + } + + cboDataFormat = new GenericBrowserButton (); + cboDataFormat.Text = "Data _format: (not selected)"; + + DataFormatReference[] dfrs = new DataFormatReference[0]; + if (Mode == FileBrowserMode.Save) + { + // show all dataformats for the current object model + Association[] assocs = Association.FromCriteria(new AssociationCriteria() { ObjectModel = ObjectModel.MakeReference() }); + List dfrlist = new List(); + foreach (Association assoc in assocs) + { + foreach (DataFormatReference dfr in assoc.DataFormats) + { + dfrlist.Add(dfr); + } + } + dfrs = dfrlist.ToArray(); + } + else if (Mode == FileBrowserMode.Open) + { + if (false) // (Accessor != null) + { + /* + // TODO: This desperately needs to be fixed; GetAvailableDataFormats should take + // an accessor, not a file name, as parameter to be cross-accessor compatible!!! + + // so... have we fixed this now? + + if (mvarAccessor is FileAccessor) + { + */ + // show all dataformats for the current accessor + dfrs = UniversalEditor.Common.Reflection.GetAvailableDataFormats(/*Accessor*/); + /* + } + else + { + dfrs = UniversalEditor.Common.Reflection.GetAvailableDataFormats(); + } + */ + } + else if (ObjectModel != null) + { + dfrs = UniversalEditor.Common.Reflection.GetAvailableDataFormats(ObjectModel.MakeReference()); + } + else + { + dfrs = UniversalEditor.Common.Reflection.GetAvailableDataFormats(); + } + } + foreach (DataFormatReference dfr in dfrs) + { + cboDataFormat.AvailableObjects.Add(dfr); + } + + + _Table = new Container (); + _Table.Layout = new BoxLayout (Orientation.Horizontal); + _Table.Controls.Add (cboObjectModel, new BoxLayout.Constraints (true, true)); + _Table.Controls.Add (cboDataFormat, new BoxLayout.Constraints (true, true)); + this.Controls.Add (_Table, new BoxLayout.Constraints (false, false)); + } + } +} + diff --git a/CSharp/Libraries/UniversalEditor.UserInterface/Dialogs/DocumentPropertiesDialogV2.cs b/CSharp/Libraries/UniversalEditor.UserInterface/Dialogs/DocumentPropertiesDialogV2.cs new file mode 100644 index 00000000..fe2b88b1 --- /dev/null +++ b/CSharp/Libraries/UniversalEditor.UserInterface/Dialogs/DocumentPropertiesDialogV2.cs @@ -0,0 +1,298 @@ +// +// DocumentPropertiesDialogV2.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using UniversalWidgetToolkit.Controls; +using UniversalWidgetToolkit; +using MBS.Framework.Drawing; +using UniversalWidgetToolkit.Layouts; +using UniversalWidgetToolkit.Controls.FileBrowser; +using UniversalWidgetToolkit.Dialogs; +using UniversalEditor.UserInterface.Controls; + +namespace UniversalEditor.UserInterface.Dialogs +{ + public class DocumentPropertiesDialogV2 : Dialog + { + public DocumentPropertiesDialogV2 () + { + this.InitializeComponent (); + this.Buttons [0].Click += cmdOK_Click; + } + + protected override void OnCreating (EventArgs e) + { + base.OnCreating (e); + this.Buttons [0].ResponseValue = (int)DialogResult.OK; + this.Buttons [1].ResponseValue = (int)DialogResult.Cancel; + + switch (Mode) + { + case DocumentPropertiesDialogMode.Open: + { + this.Text = "Open Document"; + this.Buttons [0].StockType = ButtonStockType.Open; + break; + } + case DocumentPropertiesDialogMode.Save: + { + this.Text = "Save Document"; + this.Buttons [0].StockType = ButtonStockType.Save; + break; + } + } + } + + void cmdOK_Click (object sender, EventArgs e) + { + StackSidebarPanel pnl = sidebar.SelectedPanel; + Container ct = (pnl.Control as Container); + + AccessorReference accref = pnl.GetExtraData ("ar"); + foreach (Control ctl in ct.Controls) { + CustomOption eo = (ctl.GetExtraData ("eo") as CustomOption); + if (eo == null) + continue; + + if (ctl is CheckBox) { + CheckBox itm = (ctl as CheckBox); + (eo as CustomOptionBoolean).Value = itm.Checked; + } + /* + else if (ctl is ComboBox) + { + CustomOptionFieldChoice choice = ((ctl as ComboBox).SelectedItem as CustomOptionFieldChoice); + (eo as CustomOptionChoice).Value = choice; + } + */ + else if (ctl is TextBox) { + TextBox itm = (ctl as TextBox); + if (eo is CustomOptionText) { + (eo as CustomOptionText).Value = itm.Text; + } + } else if (ctl is UniversalEditorFileBrowserControl) { + UniversalEditorFileBrowserControl fbc = (ctl as UniversalEditorFileBrowserControl); + if (eo is CustomOptionFile) + { + // (eo as CustomOptionFile).Value = fbc.SelectedFileNames [0]; + } + } + } + + Accessor acc = accref.Create (); + this.Close (); + } + + public DocumentPropertiesDialogMode Mode { get; set; } = DocumentPropertiesDialogMode.Open; + + private ObjectModel mvarInitialObjectModel = null; + + private ObjectModel mvarObjectModel = null; + public ObjectModel ObjectModel { get { return mvarObjectModel; } set { mvarObjectModel = value; mvarInitialObjectModel = value; } } + + private DataFormat mvarInitialDataFormat = null; + + private DataFormat mvarDataFormat = null; + public DataFormat DataFormat { get { return mvarDataFormat; } set { mvarDataFormat = value; mvarInitialDataFormat = value; } } + + private Accessor mvarInitialAccesor = null; + + private Accessor mvarAccessor = null; + public Accessor Accessor { get { return mvarAccessor; } set { mvarAccessor = value; mvarInitialAccesor = value; } } + + private StackSidebar sidebar = null; + + private void InitializeComponent() + { + sidebar = new StackSidebar (); + this.Layout = new BoxLayout (Orientation.Vertical); + + AccessorReference[] accessors = UniversalEditor.Common.Reflection.GetAvailableAccessors (); + foreach (AccessorReference acc in accessors) { + if (String.IsNullOrEmpty (acc.Title)) { + // the accessor doesn't have a title - interpret this to + // mean we shouldn't be showing it in the UI + continue; + } + StackSidebarPanel panel = new StackSidebarPanel (); + panel.SetExtraData ("ar", acc); + + Container ct = new Container (); + ct.Layout = new GridLayout (); + ct.Name = acc.AccessorType.FullName; + ct.Text = acc.Title; + + CustomOption.CustomOptionCollection coll = null; + switch (Mode) { + case DocumentPropertiesDialogMode.Open: + { + coll = acc.ImportOptions; + break; + } + case DocumentPropertiesDialogMode.Save: + { + coll = acc.ExportOptions; + break; + } + } + + int iRow = 0; + foreach (CustomOption eo in coll) { + // do not render the CustomOption if it's supposed to be invisible + if (!eo.Visible) continue; + + if (!(eo is CustomOptionBoolean) && (!(eo is CustomOptionFile))) + { + Label lbl = new Label(); + // lbl.FlatStyle = FlatStyle.System; + // lbl.AutoSize = true; + // lbl.Dock = DockStyle.None; + // lbl.Anchor = AnchorStyles.Left; + lbl.UseMnemonic = true; + lbl.Text = eo.Title; // .Replace("_", "&"); // only for WinForms + ct.Controls.Add(lbl, new GridLayout.Constraints(iRow, 0, 1, 1, ExpandMode.None)); + } + + if (eo is CustomOptionChoice) + { + CustomOptionChoice option = (eo as CustomOptionChoice); + + // ComboBox cbo = new ComboBox(); + // if (option.RequireChoice) cbo.DropDownStyle = ComboBoxStyle.DropDownList; + foreach (CustomOptionFieldChoice choice in option.Choices) + { + // cbo.Items.Add(choice); + } + // cbo.Dock = DockStyle.Fill; + + // tbl.Controls.Add(cbo); + + // CustomOptionControls.Add(eo.PropertyName, cbo); + } + else if (eo is CustomOptionNumber) + { + CustomOptionNumber option = (eo as CustomOptionNumber); + + TextBox txt = new TextBox(); // NumericUpDown txt = new NumericUpDown(); + txt.SetExtraData("eo", option); + if (option.MaximumValue.HasValue) + { + // txt.Maximum = option.MaximumValue.Value; + } + else + { + // txt.Maximum = Decimal.MaxValue; + } + if (option.MinimumValue.HasValue) + { + // txt.Minimum = option.MinimumValue.Value; + } + else + { + // txt.Minimum = Decimal.MinValue; + } + // txt.Value = option.DefaultValue; + + ct.Controls.Add(txt, new GridLayout.Constraints(iRow, 1, 1, 1, ExpandMode.Horizontal)); + } + else if (eo is CustomOptionText) + { + CustomOptionText option = (eo as CustomOptionText); + + TextBox txt = new TextBox(); + txt.SetExtraData("eo", option); + txt.Text = option.DefaultValue; + if (option.MaximumLength.HasValue) txt.MaxLength = option.MaximumLength.Value; + ct.Controls.Add(txt, new GridLayout.Constraints(iRow, 1, 1, 1, ExpandMode.Horizontal)); + } + else if (eo is CustomOptionBoolean) + { + CustomOptionBoolean option = (eo as CustomOptionBoolean); + + CheckBox chk = new CheckBox(); + chk.SetExtraData("eo", option); + chk.Text = option.Title; + + ct.Controls.Add(chk, new GridLayout.Constraints(iRow, 0, 1, 2, ExpandMode.Horizontal)); + } + else if (eo is CustomOptionFile) + { + CustomOptionFile option = (eo as CustomOptionFile); + + UniversalEditorFileBrowserControl fbc = new UniversalEditorFileBrowserControl (); + fbc.SetExtraData("eo", option); + // TextBox cmd = new TextBox(); + // AwesomeControls.FileTextBox.FileTextBoxControl cmd = new AwesomeControls.FileTextBox.FileTextBoxControl(); + // cmd.Click += cmdFileBrowse_Click; + // cmd.Dock = DockStyle.Fill; + fbc.SetExtraData("eo", eo); + switch (option.DialogMode) + { + case CustomOptionFileDialogMode.Open: + { + fbc.Mode = FileBrowserMode.Open; + break; + } + case CustomOptionFileDialogMode.Save: + { + fbc.Mode = FileBrowserMode.Save; + break; + } + } + ct.Controls.Add(fbc, new GridLayout.Constraints(iRow, 0, 1, 2, ExpandMode.Both)); + } + + // tbl.ColumnCount = 2; + // tbl.RowCount = CustomOptionControls.Count; + iRow++; + } + + panel.Control = ct; + sidebar.Items.Add (panel); + } + this.Controls.Add (sidebar, new BoxLayout.Constraints(true, true)); + + this.Buttons.Add (new Button (ButtonStockType.OK)); + this.Buttons [0].ResponseValue = (int)DialogResult.OK; + this.Buttons.Add (new Button (ButtonStockType.Cancel)); + this.Buttons [1].ResponseValue = (int)DialogResult.Cancel; + + switch (Mode) + { + case DocumentPropertiesDialogMode.Open: + { + this.Text = "Open Document"; + this.Buttons [0].StockType = ButtonStockType.Open; + break; + } + case DocumentPropertiesDialogMode.Save: + { + this.Text = "Save Document"; + this.Buttons [0].StockType = ButtonStockType.Save; + break; + } + } + + MinimumSize = new Dimension2D (300, 200); + Size = new Dimension2D (600, 400); + } + } +} + diff --git a/CSharp/Libraries/UniversalEditor.UserInterface/MainWindow.cs b/CSharp/Libraries/UniversalEditor.UserInterface/MainWindow.cs index c6bf8549..f522a2ee 100644 --- a/CSharp/Libraries/UniversalEditor.UserInterface/MainWindow.cs +++ b/CSharp/Libraries/UniversalEditor.UserInterface/MainWindow.cs @@ -473,6 +473,18 @@ namespace UniversalEditor.UserInterface #region IHostApplicationWindow implementation public void OpenFile() { + using (DocumentPropertiesDialogV2 dlg = new DocumentPropertiesDialogV2 ()) + { + if (dlg.ShowDialog () == DialogResult.OK) + { + if (dlg.ObjectModel == null || dlg.DataFormat == null || dlg.Accessor == null) { + return; + } + Document doc = new Document(dlg.ObjectModel, dlg.DataFormat, dlg.Accessor); + OpenFile(doc); + } + } + /* using (DocumentPropertiesDialog dlg = new DocumentPropertiesDialog()) { if (dlg.ShowDialog() == DialogResult.OK) @@ -481,6 +493,7 @@ namespace UniversalEditor.UserInterface OpenFile(doc); } } + */ } public void OpenFile(params string[] fileNames) diff --git a/CSharp/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj b/CSharp/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj index 28ca92d9..fab1173d 100644 --- a/CSharp/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj +++ b/CSharp/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj @@ -110,6 +110,9 @@ + + + @@ -155,6 +158,7 @@ +