Slowly but surely making progress toward better user interface

This commit is contained in:
Michael Becker 2019-08-01 01:22:46 -04:00
parent 20cedbf117
commit 8cee209f3b
5 changed files with 624 additions and 0 deletions

View File

@ -0,0 +1,158 @@
//
// GenericBrowserButton.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
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<TObj, TRef> : DropDownButton
where TObj : class, References<TRef>
where TRef : class, ReferencedBy<TObj>
{
public GenericBrowserButton ()
{
initct ();
}
public event EventHandler SelectionChanged;
private ListView lv = null;
private DefaultTreeModel tm = null;
public Collection<TRef> AvailableObjects { get; } = new Collection<TRef>();
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<TreeModelRowColumn> columns = new List<TreeModelRowColumn>();
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>("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>("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>("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();
}
}
}
}

View File

@ -0,0 +1,151 @@
//
// UniversalEditorFileBrowserControl.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
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<ObjectModel, ObjectModelReference> cboObjectModel = null;
private GenericBrowserButton<DataFormat, DataFormatReference> 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<ObjectModel, ObjectModelReference> ();
// 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<DataFormat, DataFormatReference> ();
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<DataFormatReference> dfrlist = new List<DataFormatReference>();
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));
}
}
}

View File

@ -0,0 +1,298 @@
//
// DocumentPropertiesDialogV2.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
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<AccessorReference> ("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<AccessorReference> ("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<CustomOption>("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);
}
}
}

View File

@ -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)

View File

@ -110,6 +110,9 @@
<Compile Include="Editors\FileSystem\FileSystemEditorSettingsProvider.cs" />
<Compile Include="Editors\Text\Plain\PlainTextEditorSettingsProvider.cs" />
<Compile Include="Dialogs\DocumentPropertiesDialogMode.cs" />
<Compile Include="Dialogs\DocumentPropertiesDialogV2.cs" />
<Compile Include="Controls\UniversalEditorFileBrowserControl.cs" />
<Compile Include="Controls\GenericBrowserButton.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
@ -155,6 +158,7 @@
<Folder Include="Editors\Text\Plain\" />
<Folder Include="Editors\FileSystem\" />
<Folder Include="Editors\PropertyList\" />
<Folder Include="Controls\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.