Move to new library model and view
- Add new listview control for library content - Migrate library providers to containers - Cloud, Sqlite, Directories, Queue, History - Migrate SideBar components to containers - Primatives, Text, Braille, ImageConverter - Create new library container types - Zip files, Calibration parts, Printer SDCards - Reduce leftnav to Library, Settings, Controls, Options - Add DragDrop support for image content
This commit is contained in:
parent
b0b249e0c3
commit
03a593f1b5
129 changed files with 7643 additions and 10331 deletions
40
Library/Widgets/ListView/IListContentView.cs
Normal file
40
Library/Widgets/ListView/IListContentView.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (c) 2017, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
public interface IListContentView
|
||||
{
|
||||
int ThumbWidth { get; }
|
||||
int ThumbHeight { get; }
|
||||
void AddItem(ListViewItem item);
|
||||
void ClearItems();
|
||||
}
|
||||
}
|
||||
172
Library/Widgets/ListView/IconListView.cs
Normal file
172
Library/Widgets/ListView/IconListView.cs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
Copyright (c) 2017, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
public class IconListView : FlowLayoutWidget, IListContentView
|
||||
{
|
||||
public int ThumbWidth { get; set; } = 128;
|
||||
public int ThumbHeight { get; set; } = 128;
|
||||
|
||||
private FlowLayoutWidget rowButtonContainer = null;
|
||||
|
||||
public IconListView()
|
||||
: base(FlowDirection.TopToBottom)
|
||||
{
|
||||
}
|
||||
|
||||
private int cellIndex = 0;
|
||||
|
||||
int columnCount = 1;
|
||||
|
||||
public override void OnBoundsChanged(EventArgs e)
|
||||
{
|
||||
columnCount = (int)Math.Floor(this.LocalBounds.Width / ThumbWidth);
|
||||
base.OnBoundsChanged(e);
|
||||
}
|
||||
|
||||
public void AddItem(ListViewItem item)
|
||||
{
|
||||
var iconView = new IconViewItem(item, this.ThumbWidth, this.ThumbHeight);
|
||||
item.ViewWidget = iconView;
|
||||
|
||||
if (rowButtonContainer == null)
|
||||
{
|
||||
rowButtonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
|
||||
rowButtonContainer.HAnchor = HAnchor.ParentLeftRight;
|
||||
|
||||
rowButtonContainer.AddChild(iconView);
|
||||
this.AddChild(rowButtonContainer);
|
||||
cellIndex = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rowButtonContainer.AddChild(iconView);
|
||||
|
||||
if (cellIndex++ >= columnCount - 1)
|
||||
{
|
||||
rowButtonContainer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearItems()
|
||||
{
|
||||
rowButtonContainer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class IconViewItem : ListViewItemBase
|
||||
{
|
||||
public IconViewItem(ListViewItem item, int thumbWidth, int thumbHeight)
|
||||
: base(item, thumbWidth, thumbHeight)
|
||||
{
|
||||
this.VAnchor = VAnchor.FitToChildren;
|
||||
this.HAnchor = HAnchor.FitToChildren;
|
||||
this.Padding = 4;
|
||||
this.Margin = new BorderDouble(6, 0, 0, 6);
|
||||
|
||||
var container = new FlowLayoutWidget(FlowDirection.TopToBottom);
|
||||
this.AddChild(container);
|
||||
|
||||
imageWidget = new ImageWidget(thumbWidth, thumbHeight)
|
||||
{
|
||||
AutoResize = false,
|
||||
Name = "List Item Thumbnail",
|
||||
BackgroundColor = item.ListView.ThumbnailBackground,
|
||||
Margin = 0,
|
||||
};
|
||||
|
||||
imageWidget.Click += (sender, e) =>
|
||||
{
|
||||
if (listViewItem.Model is ILibraryContentItem)
|
||||
{
|
||||
if (this.IsSelected)
|
||||
{
|
||||
listViewItem.ListView.SelectedItems.Remove(listViewItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Keyboard.IsKeyDown(Keys.ControlKey))
|
||||
{
|
||||
listViewItem.ListView.SelectedItems.Clear();
|
||||
}
|
||||
|
||||
listViewItem.ListView.SelectedItems.Add(listViewItem);
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
container.AddChild(imageWidget);
|
||||
|
||||
int maxWidth = thumbWidth - 4;
|
||||
|
||||
var text = new TextWidget(item.Model.Name, 0, 0, 9, textColor: ActiveTheme.Instance.PrimaryTextColor)
|
||||
{
|
||||
AutoExpandBoundsToText = false,
|
||||
EllipsisIfClipped = true,
|
||||
HAnchor = HAnchor.ParentCenter,
|
||||
Margin = new BorderDouble(0, 0, 0, 3),
|
||||
};
|
||||
|
||||
text.MaximumSize = new Vector2(maxWidth, 20);
|
||||
if (text.Printer.LocalBounds.Width > maxWidth)
|
||||
{
|
||||
text.Width = maxWidth;
|
||||
text.Text = item.Model.Name;
|
||||
}
|
||||
|
||||
container.AddChild(text);
|
||||
}
|
||||
|
||||
public override async void OnLoad(EventArgs args)
|
||||
{
|
||||
base.OnLoad(args);
|
||||
await this.LoadItemThumbnail();
|
||||
}
|
||||
|
||||
public override RGBA_Bytes BackgroundColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.IsSelected ? ActiveTheme.Instance.PrimaryAccentColor : RGBA_Bytes.Transparent;
|
||||
}
|
||||
set { }
|
||||
}
|
||||
}
|
||||
}
|
||||
357
Library/Widgets/ListView/ListView.cs
Normal file
357
Library/Widgets/ListView/ListView.cs
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
Copyright (c) 2017, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.PlatformAbstract;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
|
||||
|
||||
public class ListView : ScrollableWidget
|
||||
{
|
||||
private EventHandler unregisterEvents;
|
||||
|
||||
private bool editMode = false;
|
||||
|
||||
internal GuiWidget contentView;
|
||||
|
||||
private ILibraryContext LibraryContext;
|
||||
|
||||
public ListView(ILibraryContext context)
|
||||
{
|
||||
this.LibraryContext = context;
|
||||
|
||||
// Set Display Attributes
|
||||
this.MinimumSize = new Vector2(0, 200);
|
||||
this.AnchorAll();
|
||||
this.BackgroundColor = ActiveTheme.Instance.TertiaryBackgroundColor;
|
||||
this.AutoScroll = true;
|
||||
this.ScrollArea.Padding = new BorderDouble(3);
|
||||
|
||||
// AddWatermark
|
||||
string imagePath = Path.Combine("OEMSettings", "watermark.png");
|
||||
if (StaticData.Instance.FileExists(imagePath))
|
||||
{
|
||||
this.AddChildToBackground(new ImageWidget(StaticData.Instance.LoadImage(imagePath))
|
||||
{
|
||||
VAnchor = VAnchor.ParentCenter,
|
||||
HAnchor = HAnchor.ParentCenter
|
||||
});
|
||||
}
|
||||
|
||||
this.ScrollArea.HAnchor = HAnchor.ParentLeftRight;
|
||||
|
||||
AutoScroll = true;
|
||||
|
||||
this.ListContentView = new IconListView();
|
||||
context.ContainerChanged += ActiveContainer_Changed;
|
||||
context.ContainerReloaded += ActiveContainer_Reloaded;
|
||||
}
|
||||
|
||||
public ILibraryContainer ActiveContainer => this.LibraryContext.ActiveContainer;
|
||||
|
||||
public RGBA_Bytes ThumbnailBackground { get; } = ActiveTheme.Instance.TertiaryBackgroundColor.AdjustLightness(1.1).GetAsRGBA_Bytes();
|
||||
public RGBA_Bytes ThumbnailForeground { get; set; } = ActiveTheme.Instance.PrimaryAccentColor;
|
||||
|
||||
private GuiWidget stashedView = null;
|
||||
|
||||
private void ActiveContainer_Changed(object sender, ContainerChangedEventArgs e)
|
||||
{
|
||||
var activeContainer = e.ActiveContainer;
|
||||
|
||||
var containerDefaultView = activeContainer?.DefaultView;
|
||||
|
||||
if (containerDefaultView != null
|
||||
&& containerDefaultView != this.ListContentView)
|
||||
{
|
||||
stashedView = this.contentView;
|
||||
// Critical that assign to the contentView backing field and not the ListContentView property that uses it
|
||||
this.SetContentView(activeContainer.DefaultView);
|
||||
}
|
||||
else if (stashedView != null)
|
||||
{
|
||||
this.SetContentView(stashedView);
|
||||
stashedView = null;
|
||||
}
|
||||
|
||||
DisplayContainerContent(activeContainer);
|
||||
}
|
||||
|
||||
private void ActiveContainer_Reloaded(object sender, EventArgs e)
|
||||
{
|
||||
DisplayContainerContent(ActiveContainer);
|
||||
}
|
||||
|
||||
private List<ListViewItem> items = new List<ListViewItem>();
|
||||
|
||||
public IEnumerable<ListViewItem> Items => items;
|
||||
|
||||
/*
|
||||
* bool isTraceable = listViewItem.Model is ILibraryPrintItem;
|
||||
bool hasID = !string.IsNullOrEmpty(listViewItem.Model.ID);
|
||||
List<ListViewItem> acquireItems,
|
||||
if (hasID
|
||||
&& isTraceable
|
||||
&& thumbnail == null)
|
||||
{
|
||||
// Schedule for collection, display default thumb until then
|
||||
acquireItems.Add(listViewItem);
|
||||
}
|
||||
*/
|
||||
/// <summary>
|
||||
/// Empties the list children and repopulates the list with the source container content
|
||||
/// </summary>
|
||||
/// <param name="sourceContainer">The container to load</param>
|
||||
/// <returns>Async Task</returns>
|
||||
private async Task DisplayContainerContent(ILibraryContainer sourceContainer)
|
||||
{
|
||||
if (sourceContainer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var itemsNeedingLoad = new List<ListViewItem>();
|
||||
|
||||
this.items.Clear();
|
||||
|
||||
this.SelectedItems.Clear();
|
||||
contentView.CloseAllChildren();
|
||||
|
||||
var itemsContentView = contentView as IListContentView;
|
||||
itemsContentView.ClearItems();
|
||||
|
||||
int width = itemsContentView.ThumbWidth;
|
||||
int height = itemsContentView.ThumbHeight;
|
||||
|
||||
// TODO: Disabled to consider upfolder on breadcrumb bar
|
||||
if (sourceContainer.Parent != null && false)
|
||||
{
|
||||
var icon = LibraryProviderHelpers.LoadInvertIcon("FileDialog", "up_folder.png");
|
||||
icon = ResizeCanvas(icon, width, height);
|
||||
|
||||
// Up folder item
|
||||
var item = new DynamicContainerLink("..", icon, null);
|
||||
var listViewItem = new ListViewItem(item, this)
|
||||
{
|
||||
Text = "..",
|
||||
};
|
||||
|
||||
listViewItem.DoubleClick += listViewItem_DoubleClick;
|
||||
|
||||
items.Add(listViewItem);
|
||||
itemsContentView.AddItem(listViewItem);
|
||||
}
|
||||
|
||||
// Folder items
|
||||
foreach (var childContainer in sourceContainer.ChildContainers.Where(c => c.IsVisible))
|
||||
{
|
||||
var listViewItem = new ListViewItem(childContainer, this);
|
||||
listViewItem.DoubleClick += listViewItem_DoubleClick;
|
||||
|
||||
items.Add(listViewItem);
|
||||
itemsContentView.AddItem(listViewItem);
|
||||
}
|
||||
|
||||
// List items
|
||||
foreach (var item in sourceContainer.Items.Where(i => i.IsVisible))
|
||||
{
|
||||
var listViewItem = new ListViewItem(item, this);
|
||||
listViewItem.DoubleClick += listViewItem_DoubleClick;
|
||||
|
||||
items.Add(listViewItem);
|
||||
itemsContentView.AddItem(listViewItem);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ViewMode
|
||||
{
|
||||
Icons,
|
||||
List
|
||||
}
|
||||
|
||||
private void SetContentView(GuiWidget contentView)
|
||||
{
|
||||
this.ScrollArea.CloseAllChildren();
|
||||
|
||||
this.contentView = contentView;
|
||||
this.contentView.HAnchor = HAnchor.ParentLeftRight;
|
||||
this.contentView.Name = "Library ListView";
|
||||
this.AddChild(this.contentView);
|
||||
}
|
||||
|
||||
public GuiWidget ListContentView
|
||||
{
|
||||
get { return contentView; }
|
||||
set
|
||||
{
|
||||
if (value is IListContentView)
|
||||
{
|
||||
SetContentView(value);
|
||||
|
||||
// Allow some time for layout to occur and contentView to become sized before loading content
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
DisplayContainerContent(ActiveContainer);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException("ListContentView must be assignable from IListContentView");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal ImageBuffer LoadCachedImage(ListViewItem listViewItem)
|
||||
{
|
||||
string cachePath = ApplicationController.Instance.CachePath(listViewItem.Model);
|
||||
|
||||
bool isCached = !string.IsNullOrEmpty(cachePath) && File.Exists(cachePath);
|
||||
if (isCached)
|
||||
{
|
||||
ImageBuffer thumbnail = new ImageBuffer();
|
||||
ImageIO.LoadImageData(cachePath, thumbnail);
|
||||
thumbnail.SetRecieveBlender(new BlenderPreMultBGRA());
|
||||
|
||||
return thumbnail.MultiplyWithPrimaryAccent();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: ResizeCanvas is also colorizing thumbnails as a proof of concept
|
||||
public ImageBuffer ResizeCanvas(ImageBuffer originalImage, int width, int height)
|
||||
{
|
||||
var destImage = new ImageBuffer(width, height, 32, originalImage.GetRecieveBlender());
|
||||
|
||||
var renderGraphics = destImage.NewGraphics2D();
|
||||
renderGraphics.Clear(this.ThumbnailBackground);
|
||||
|
||||
var x = width / 2 - originalImage.Width / 2;
|
||||
var y = height / 2 - originalImage.Height / 2;
|
||||
|
||||
var center = new RectangleInt(x, y + originalImage.Height, x + originalImage.Width, y);
|
||||
//renderGraphics.FillRectangle(center, this.ThumbnailForeground);
|
||||
|
||||
renderGraphics.ImageRenderQuality = Graphics2D.TransformQuality.Best;
|
||||
|
||||
//originalImage = originalImage.Multiply(this.ThumbnailBackground);
|
||||
|
||||
renderGraphics.Render(originalImage, width /2 - originalImage.Width /2, height /2 - originalImage.Height /2);
|
||||
|
||||
renderGraphics.FillRectangle(center, RGBA_Bytes.Transparent);
|
||||
|
||||
return destImage;
|
||||
}
|
||||
|
||||
private void listViewItem_DoubleClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
UiThread.RunOnIdle(async () =>
|
||||
{
|
||||
var listViewItem = sender as ListViewItem;
|
||||
var itemModel = listViewItem.Model;
|
||||
|
||||
if (listViewItem?.Text == "..")
|
||||
{
|
||||
// Up folder tiem
|
||||
if (ActiveContainer?.Parent != null)
|
||||
{
|
||||
LoadContainer(ActiveContainer.Parent);
|
||||
}
|
||||
}
|
||||
else if (itemModel is ILibraryContainerLink)
|
||||
{
|
||||
// Container items
|
||||
var containerLink = itemModel as ILibraryContainerLink;
|
||||
if (containerLink != null)
|
||||
{
|
||||
var container = await containerLink.GetContainer(null);
|
||||
container.Parent = ActiveContainer;
|
||||
|
||||
LoadContainer(container);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// List items
|
||||
var contentModel = itemModel as ILibraryContentStream;
|
||||
if (contentModel != null)
|
||||
{
|
||||
listViewItem.StartProgress();
|
||||
|
||||
var result = contentModel.CreateContent(listViewItem.ProgressReporter);
|
||||
if (result.Object3D != null)
|
||||
{
|
||||
var scene = MatterControlApplication.Instance.ActiveView3DWidget.Scene;
|
||||
|
||||
scene.ModifyChildren(children =>
|
||||
{
|
||||
children.Add(result.Object3D);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
listViewItem.EndProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void LoadContainer(ILibraryContainer temp)
|
||||
{
|
||||
this.LibraryContext.ActiveContainer = temp;
|
||||
}
|
||||
|
||||
public ObservableCollection<ListViewItem> SelectedItems { get; } = new ObservableCollection<ListViewItem>();
|
||||
|
||||
public ListViewItem DragSourceRowItem { get; set; }
|
||||
|
||||
public override void OnClosed(ClosedEventArgs e)
|
||||
{
|
||||
if (this.LibraryContext != null)
|
||||
{
|
||||
this.LibraryContext.ContainerChanged -= this.ActiveContainer_Changed;
|
||||
this.LibraryContext.ContainerReloaded -= this.ActiveContainer_Reloaded;
|
||||
}
|
||||
|
||||
unregisterEvents?.Invoke(this, null);
|
||||
base.OnClosed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
108
Library/Widgets/ListView/ListViewItem.cs
Normal file
108
Library/Widgets/ListView/ListViewItem.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Copyright (c) 2017, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
public class ListViewItem
|
||||
{
|
||||
public ILibraryItem Model { get; }
|
||||
public ListView ListView { get; }
|
||||
public string Text { get; internal set; }
|
||||
|
||||
public GuiWidget ProgressTarget { get; internal set; }
|
||||
|
||||
public ListViewItemBase ViewWidget { get; set; }
|
||||
|
||||
ProgressControl processingProgressControl;
|
||||
|
||||
internal void ProgressReporter(double progress0To1, string processingState, out bool continueProcessing)
|
||||
{
|
||||
continueProcessing = true;
|
||||
|
||||
if (processingProgressControl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
processingProgressControl.Visible = progress0To1 != 0;
|
||||
processingProgressControl.RatioComplete = progress0To1;
|
||||
processingProgressControl.ProcessType = processingState;
|
||||
|
||||
if (progress0To1 == 1)
|
||||
{
|
||||
EndProgress();
|
||||
}
|
||||
}
|
||||
|
||||
public ListViewItem(ILibraryItem listItemData, ListView dragConsumer)
|
||||
{
|
||||
this.ListView = dragConsumer;
|
||||
this.Model = listItemData;
|
||||
}
|
||||
|
||||
public event EventHandler<MouseEventArgs> DoubleClick;
|
||||
|
||||
internal void OnDoubleClick()
|
||||
{
|
||||
DoubleClick?.Invoke(this, null);
|
||||
}
|
||||
|
||||
public void StartProgress()
|
||||
{
|
||||
processingProgressControl = new ProgressControl("Loading...".Localize(), RGBA_Bytes.Black, ActiveTheme.Instance.SecondaryAccentColor, (int)(100 * GuiWidget.DeviceScale), 5, 0)
|
||||
{
|
||||
PointSize = 8,
|
||||
Margin = 0,
|
||||
Visible = true
|
||||
};
|
||||
|
||||
ProgressTarget?.AddChild(processingProgressControl);
|
||||
}
|
||||
|
||||
public void EndProgress()
|
||||
{
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
if (processingProgressControl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
processingProgressControl.Close();
|
||||
processingProgressControl = null;
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
338
Library/Widgets/ListView/ListViewItemBase.cs
Normal file
338
Library/Widgets/ListView/ListViewItemBase.cs
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
Copyright (c) 2017, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
public class ListViewItemBase : GuiWidget
|
||||
{
|
||||
private static ImageBuffer defaultFolderIcon = LibraryProviderHelpers.LoadInvertIcon("FileDialog", "folder.png");
|
||||
private static ImageBuffer defaultItemIcon = LibraryProviderHelpers.LoadInvertIcon("FileDialog", "file.png");
|
||||
private static ImageBuffer generatingThumbnailIcon = LibraryProviderHelpers.LoadInvertIcon("building_thumbnail_40x40.png");
|
||||
|
||||
protected ListViewItem listViewItem;
|
||||
protected View3DWidget view3DWidget;
|
||||
protected bool mouseInBounds = false;
|
||||
private bool mouseDownInBounds = false;
|
||||
private Vector2 mouseDownAt;
|
||||
|
||||
protected ImageWidget imageWidget;
|
||||
protected int thumbWidth;
|
||||
protected int thumbHeight;
|
||||
|
||||
public ListViewItemBase(ListViewItem listViewItem, int width, int height)
|
||||
{
|
||||
this.listViewItem = listViewItem;
|
||||
this.thumbWidth = width;
|
||||
this.thumbHeight = height;
|
||||
}
|
||||
|
||||
protected async Task LoadItemThumbnail()
|
||||
{
|
||||
var listView = listViewItem.ListView;
|
||||
|
||||
var thumbnail = listView.LoadCachedImage(listViewItem);
|
||||
if (thumbnail != null)
|
||||
{
|
||||
SetItemThumbnail(thumbnail);
|
||||
return;
|
||||
}
|
||||
|
||||
var itemModel = listViewItem.Model;
|
||||
|
||||
if (thumbnail == null)
|
||||
{
|
||||
// Ask the container - allows the container to provide its own interpretation of the item thumbnail
|
||||
thumbnail = await listView.ActiveContainer.GetThumbnail(itemModel, thumbWidth, thumbHeight);
|
||||
}
|
||||
|
||||
if (thumbnail == null && itemModel is IThumbnail)
|
||||
{
|
||||
// If the item provides its own thumbnail, try to collect it
|
||||
thumbnail = await (itemModel as IThumbnail).GetThumbnail(thumbWidth, thumbHeight);
|
||||
}
|
||||
|
||||
if (thumbnail == null)
|
||||
{
|
||||
// Ask content provider - allows type specific thumbnail creation
|
||||
var contentProvider = ApplicationController.Instance.Library.GetContentProvider(itemModel);
|
||||
if (contentProvider != null
|
||||
&& contentProvider is MeshContentProvider)
|
||||
{
|
||||
// Before we have a thumbnail set to the content specific thumbnail
|
||||
thumbnail = contentProvider.DefaultImage.AlphaToPrimaryAccent();
|
||||
|
||||
ApplicationController.Instance.QueueForGeneration(async () =>
|
||||
{
|
||||
// TODO: What we really want here is to determine if the control is being drawn because it's in the visible region of its parent
|
||||
if (this.Visible)
|
||||
{
|
||||
|
||||
SetItemThumbnail(generatingThumbnailIcon.AlphaToPrimaryAccent());
|
||||
|
||||
// Then try to load a content specific thumbnail
|
||||
await contentProvider.GetThumbnail(
|
||||
itemModel,
|
||||
thumbWidth,
|
||||
thumbHeight,
|
||||
(image) =>
|
||||
{
|
||||
// Use the content providers default image if an image failed to load
|
||||
SetItemThumbnail(image ?? contentProvider.DefaultImage, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (contentProvider != null)
|
||||
{
|
||||
// Then try to load a content specific thumbnail
|
||||
await contentProvider.GetThumbnail(
|
||||
itemModel,
|
||||
thumbWidth,
|
||||
thumbHeight,
|
||||
(image) => thumbnail = image);
|
||||
}
|
||||
}
|
||||
|
||||
if (thumbnail == null)
|
||||
{
|
||||
// Use the listview defaults
|
||||
thumbnail = ((itemModel is ILibraryContainerLink) ? defaultFolderIcon : defaultItemIcon).AlphaToPrimaryAccent();
|
||||
}
|
||||
|
||||
SetItemThumbnail(thumbnail);
|
||||
}
|
||||
|
||||
protected void SetItemThumbnail(ImageBuffer thumbnail, bool colorize = false)
|
||||
{
|
||||
if (thumbnail != null)
|
||||
{
|
||||
// Resize canvas to target as fallback
|
||||
if (thumbnail.Width < thumbWidth || thumbnail.Height < thumbHeight)
|
||||
{
|
||||
thumbnail = listViewItem.ListView.ResizeCanvas(thumbnail, thumbWidth, thumbHeight);
|
||||
}
|
||||
else if (thumbnail.Width > thumbWidth || thumbnail.Height > thumbHeight)
|
||||
{
|
||||
thumbnail = LibraryProviderHelpers.ResizeImage(thumbnail, thumbWidth, thumbHeight);
|
||||
}
|
||||
|
||||
// TODO: Resolve and implement
|
||||
// Allow the container to draw an overlay - use signal interface or add method to interface?
|
||||
//var iconWithOverlay = ActiveContainer.DrawOverlay()
|
||||
|
||||
this.imageWidget.Image = thumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDraw(Graphics2D graphics2D)
|
||||
{
|
||||
base.OnDraw(graphics2D);
|
||||
|
||||
var widgetBorder = new RoundedRect(LocalBounds, 0);
|
||||
|
||||
// Draw the hover border if the mouse is in bounds or if its the ActivePrint item
|
||||
if (mouseInBounds || (this.IsActivePrint && !this.EditMode))
|
||||
{
|
||||
//Draw interior border
|
||||
graphics2D.Render(new Stroke(widgetBorder, 3), ActiveTheme.Instance.SecondaryAccentColor);
|
||||
}
|
||||
|
||||
if (this.IsHoverItem)
|
||||
{
|
||||
RectangleDouble Bounds = LocalBounds;
|
||||
RoundedRect rectBorder = new RoundedRect(Bounds, 0);
|
||||
|
||||
this.BackgroundColor = RGBA_Bytes.White;
|
||||
|
||||
graphics2D.Render(new Stroke(rectBorder, 3), ActiveTheme.Instance.SecondaryAccentColor);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMouseDown(MouseEventArgs mouseEvent)
|
||||
{
|
||||
mouseDownInBounds = true;
|
||||
mouseDownAt = mouseEvent.Position;
|
||||
|
||||
if (IsDoubleClick(mouseEvent))
|
||||
{
|
||||
listViewItem.OnDoubleClick();
|
||||
}
|
||||
|
||||
// On mouse down update the view3DWidget reference that will be used in MouseMove and MouseUp
|
||||
view3DWidget = MatterControlApplication.Instance.ActiveView3DWidget;
|
||||
|
||||
base.OnMouseDown(mouseEvent);
|
||||
}
|
||||
|
||||
public override void OnMouseMove(MouseEventArgs mouseEvent)
|
||||
{
|
||||
var delta = mouseDownAt - mouseEvent.Position;
|
||||
|
||||
bool dragActive = mouseDownInBounds && delta.Length > 40;
|
||||
// If dragging and the drag threshold has been hit, start a drag operation but loading the drag items
|
||||
if (dragActive
|
||||
&& (listViewItem.Model is ILibraryContentStream || listViewItem.Model is ILibraryContentItem))
|
||||
{
|
||||
if (view3DWidget != null && view3DWidget.DragDropSource == null)
|
||||
{
|
||||
if (listViewItem.Model is ILibraryContentStream)
|
||||
{
|
||||
// Use provider to acquire Object3D
|
||||
var contentModel = listViewItem.Model as ILibraryContentStream;
|
||||
|
||||
// Update the ListView pointer for the dragging item
|
||||
listViewItem.ListView.DragSourceRowItem = listViewItem;
|
||||
|
||||
var contentResult = contentModel.CreateContent();
|
||||
if (contentResult != null)
|
||||
{
|
||||
// Assign a new drag source
|
||||
view3DWidget.DragDropSource = contentResult.Object3D;
|
||||
}
|
||||
}
|
||||
else if (listViewItem.Model is ILibraryContentItem)
|
||||
{
|
||||
(listViewItem.Model as ILibraryContentItem).GetContent(null).ContinueWith((task) =>
|
||||
{
|
||||
view3DWidget.DragDropSource = task.Result;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Performs move in View3DWidget and indicates if add occurred
|
||||
var screenSpaceMousePosition = this.TransformToScreenSpace(mouseEvent.Position);
|
||||
view3DWidget.AltDragOver(screenSpaceMousePosition);
|
||||
}
|
||||
|
||||
base.OnMouseMove(mouseEvent);
|
||||
}
|
||||
|
||||
public override void OnMouseUp(MouseEventArgs mouseEvent)
|
||||
{
|
||||
if (view3DWidget?.DragDropSource != null && view3DWidget.Scene.Children.Contains(view3DWidget.DragDropSource))
|
||||
{
|
||||
// Mouse and widget positions
|
||||
var screenSpaceMousePosition = this.TransformToScreenSpace(mouseEvent.Position);
|
||||
var meshViewerPosition = this.view3DWidget.meshViewerWidget.TransformToScreenSpace(view3DWidget.meshViewerWidget.LocalBounds);
|
||||
|
||||
// If the mouse is not within the meshViewer, remove the inserted drag item
|
||||
if (!meshViewerPosition.Contains(screenSpaceMousePosition))
|
||||
{
|
||||
view3DWidget.Scene.ModifyChildren(children => children.Remove(view3DWidget.DragDropSource));
|
||||
view3DWidget.Scene.ClearSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create and push the undo operation
|
||||
view3DWidget.AddUndoOperation(
|
||||
new InsertCommand(view3DWidget, view3DWidget.DragDropSource));
|
||||
}
|
||||
|
||||
view3DWidget.FinishDrop();
|
||||
}
|
||||
|
||||
mouseDownInBounds = false;
|
||||
base.OnMouseUp(mouseEvent);
|
||||
}
|
||||
|
||||
public override void OnMouseEnterBounds(MouseEventArgs mouseEvent)
|
||||
{
|
||||
base.OnMouseEnterBounds(mouseEvent);
|
||||
mouseInBounds = true;
|
||||
UpdateHoverState();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public override void OnMouseLeaveBounds(MouseEventArgs mouseEvent)
|
||||
{
|
||||
mouseInBounds = false;
|
||||
base.OnMouseLeaveBounds(mouseEvent);
|
||||
UpdateHoverState();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected virtual void UpdateColors()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual async void UpdateHoverState()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool IsHoverItem { get; set; }
|
||||
public virtual bool EditMode { get; set; }
|
||||
|
||||
private bool isActivePrint = false;
|
||||
public bool IsActivePrint
|
||||
{
|
||||
get
|
||||
{
|
||||
return isActivePrint;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (isActivePrint != value)
|
||||
{
|
||||
isActivePrint = value;
|
||||
UpdateColors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool isSelected = false;
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get
|
||||
{
|
||||
return isSelected;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (isSelected != value)
|
||||
{
|
||||
//selectionCheckBox.Checked = value;
|
||||
|
||||
isSelected = value;
|
||||
UpdateColors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Library/Widgets/ListView/PrintItemAction.cs
Normal file
62
Library/Widgets/ListView/PrintItemAction.cs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright (c) 2017, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
|
||||
namespace MatterHackers.MatterControl.PrintQueue
|
||||
{
|
||||
public class PrintItemAction
|
||||
{
|
||||
public string Title { get; set; }
|
||||
|
||||
public Action<IEnumerable<ILibraryItem>, ListView> Action { get; set; }
|
||||
|
||||
public bool AllowMultiple { get; set; } = false;
|
||||
public bool AllowProtected { get; set; } = false;
|
||||
public bool AllowContainers { get; set; } = false;
|
||||
public bool AlwaysEnabled { get; set; } = false;
|
||||
internal MenuItem MenuItem { get; set; }
|
||||
}
|
||||
|
||||
public class MenuSeparator : PrintItemAction
|
||||
{
|
||||
public MenuSeparator(string section)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class PrintItemMenuExtension
|
||||
{
|
||||
public abstract IEnumerable<PrintItemAction> GetMenuItems();
|
||||
}
|
||||
}
|
||||
425
Library/Widgets/ListView/RowListView.cs
Normal file
425
Library/Widgets/ListView/RowListView.cs
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
Copyright (c) 2017, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
public class RowListView : FlowLayoutWidget, IListContentView
|
||||
{
|
||||
public int ThumbWidth { get; } = 50;
|
||||
public int ThumbHeight { get; } = 50;
|
||||
|
||||
public RowListView()
|
||||
: base(FlowDirection.TopToBottom)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddItem(ListViewItem item)
|
||||
{
|
||||
var detailsView = new RowViewItem(item, this.ThumbWidth, this.ThumbHeight);
|
||||
this.AddChild(detailsView);
|
||||
|
||||
item.ViewWidget = detailsView;
|
||||
}
|
||||
|
||||
public void ClearItems()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RowViewItem : ListViewItemBase
|
||||
{
|
||||
private CheckBox selectionCheckBox;
|
||||
|
||||
private SlideWidget actionButtonContainer;
|
||||
|
||||
private ConditionalClickWidget conditionalClickContainer;
|
||||
|
||||
private TextWidget partLabel;
|
||||
|
||||
private GuiWidget middleColumn;
|
||||
|
||||
//private TextWidget partStatus;
|
||||
|
||||
private GuiWidget selectionCheckBoxContainer;
|
||||
|
||||
private FatFlatClickWidget viewButton;
|
||||
|
||||
private TextWidget viewButtonLabel;
|
||||
|
||||
private event EventHandler unregisterEvents;
|
||||
|
||||
public RowViewItem(ListViewItem listViewItem, int thumbWidth, int thumbHeight)
|
||||
: base(listViewItem, thumbWidth, thumbHeight)
|
||||
{
|
||||
// Set Display Attributes
|
||||
this.VAnchor = VAnchor.FitToChildren;
|
||||
this.HAnchor = HAnchor.ParentLeftRight | HAnchor.FitToChildren;
|
||||
this.Height = 50;
|
||||
this.BackgroundColor = RGBA_Bytes.White;
|
||||
this.Padding = new BorderDouble(0);
|
||||
this.Margin = new BorderDouble(6, 0, 6, 6);
|
||||
|
||||
var topToBottomLayout = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.ParentLeftRight };
|
||||
|
||||
var topContentsFlowLayout = new FlowLayoutWidget(FlowDirection.LeftToRight) { HAnchor = HAnchor.ParentLeftRight };
|
||||
{
|
||||
selectionCheckBoxContainer = new GuiWidget()
|
||||
{
|
||||
VAnchor = VAnchor.ParentBottomTop,
|
||||
Width = 40,
|
||||
Visible = false,
|
||||
Margin = new BorderDouble(left: 6)
|
||||
};
|
||||
|
||||
selectionCheckBox = new CheckBox("")
|
||||
{
|
||||
Name = "List Item Checkbox",
|
||||
VAnchor = VAnchor.ParentCenter,
|
||||
HAnchor = HAnchor.ParentCenter
|
||||
};
|
||||
selectionCheckBoxContainer.AddChild(selectionCheckBox);
|
||||
|
||||
var leftColumn = new FlowLayoutWidget(FlowDirection.LeftToRight)
|
||||
{
|
||||
VAnchor = VAnchor.ParentTop | VAnchor.FitToChildren
|
||||
};
|
||||
topContentsFlowLayout.AddChild(leftColumn);
|
||||
|
||||
// TODO: add in default thumbnail handling from parent or IListItem
|
||||
imageWidget = new ImageWidget(thumbWidth, thumbHeight)
|
||||
{
|
||||
Name = "List Item Thumbnail",
|
||||
BackgroundColor = ActiveTheme.Instance.PrimaryAccentColor
|
||||
};
|
||||
leftColumn.AddChild(imageWidget);
|
||||
|
||||
// TODO: Move to caller
|
||||
// TextInfo textInfo = new CultureInfo("en-US", false).TextInfo;
|
||||
// textInfo.ToTitleCase(PrintItemWrapper.Name).Replace('_', ' ')
|
||||
|
||||
partLabel = new TextWidget(listViewItem.Model.Name, pointSize: 14)
|
||||
{
|
||||
TextColor = RGBA_Bytes.Black,
|
||||
MinimumSize = new Vector2(1, 18),
|
||||
VAnchor = VAnchor.ParentCenter
|
||||
};
|
||||
|
||||
/*
|
||||
partStatus = new TextWidget("{0}: {1}".FormatWith("Status".Localize().ToUpper(), "Queued to Print".Localize()), pointSize: 10)
|
||||
{
|
||||
AutoExpandBoundsToText = true,
|
||||
TextColor = RGBA_Bytes.Black,
|
||||
MinimumSize = new Vector2(50, 12)
|
||||
middleColumn.AddChild(partStatus);
|
||||
|
||||
}; */
|
||||
|
||||
middleColumn = new GuiWidget(0.0, 0.0)
|
||||
{
|
||||
VAnchor = VAnchor.ParentBottomTop,
|
||||
HAnchor = HAnchor.ParentLeftRight,
|
||||
Padding = 0,
|
||||
Margin = new BorderDouble(10, 3)
|
||||
};
|
||||
|
||||
listViewItem.ProgressTarget = middleColumn;
|
||||
|
||||
bool mouseDownOnMiddle = false;
|
||||
middleColumn.MouseDown += (sender, e) =>
|
||||
{
|
||||
// TODO: Need custom model type for non-content items
|
||||
// Abort normal processing for view helpers
|
||||
/* if (this.IsViewHelperItem)
|
||||
{
|
||||
return;
|
||||
}*/
|
||||
mouseDownOnMiddle = true;
|
||||
};
|
||||
|
||||
middleColumn.MouseUp += (sender, e) =>
|
||||
{
|
||||
if (mouseDownOnMiddle
|
||||
&& listViewItem.Model is ILibraryContentItem
|
||||
&& middleColumn.LocalBounds.Contains(e.Position))
|
||||
{
|
||||
// TODO: Resolve missing .EditMode condition
|
||||
if (false /*this.libraryDataView.EditMode*/)
|
||||
{
|
||||
if (this.IsSelected)
|
||||
{
|
||||
listViewItem.ListView.SelectedItems.Remove(listViewItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
listViewItem.ListView.SelectedItems.Remove(listViewItem);
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.IsSelected)
|
||||
{
|
||||
if (!Keyboard.IsKeyDown(Keys.ControlKey))
|
||||
{
|
||||
listViewItem.ListView.SelectedItems.Clear();
|
||||
}
|
||||
|
||||
listViewItem.ListView.SelectedItems.Add(listViewItem);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mouseDownOnMiddle = false;
|
||||
};
|
||||
|
||||
middleColumn.AddChild(partLabel);
|
||||
|
||||
topContentsFlowLayout.AddChild(middleColumn);
|
||||
}
|
||||
|
||||
// The ConditionalClickWidget supplies a user driven Enabled property based on a delegate of your choosing
|
||||
conditionalClickContainer = new ConditionalClickWidget(() => this.EditMode)
|
||||
{
|
||||
HAnchor = HAnchor.ParentLeftRight,
|
||||
VAnchor = VAnchor.ParentBottomTop
|
||||
};
|
||||
conditionalClickContainer.Click += onQueueItemClick;
|
||||
|
||||
topToBottomLayout.AddChild(topContentsFlowLayout);
|
||||
this.AddChild(topToBottomLayout);
|
||||
|
||||
actionButtonContainer = getItemActionButtons();
|
||||
actionButtonContainer.Visible = false;
|
||||
this.AddChild(conditionalClickContainer);
|
||||
|
||||
this.AddChild(actionButtonContainer);
|
||||
}
|
||||
|
||||
public override async void OnLoad(EventArgs args)
|
||||
{
|
||||
base.OnLoad(args);
|
||||
await this.LoadItemThumbnail();
|
||||
}
|
||||
|
||||
private bool isHoverItem = false;
|
||||
public override bool IsHoverItem
|
||||
{
|
||||
get { return isHoverItem; }
|
||||
set
|
||||
{
|
||||
if (this.isHoverItem != value)
|
||||
{
|
||||
this.isHoverItem = value;
|
||||
if (value && !this.EditMode)
|
||||
{
|
||||
this.actionButtonContainer.SlideIn();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.actionButtonContainer.SlideOut();
|
||||
}
|
||||
|
||||
UpdateColors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnClosed(ClosedEventArgs e)
|
||||
{
|
||||
unregisterEvents?.Invoke(this, null);
|
||||
base.OnClosed(e);
|
||||
}
|
||||
|
||||
protected override void UpdateColors()
|
||||
{
|
||||
base.UpdateColors();
|
||||
|
||||
if (this.IsActivePrint && !this.EditMode)
|
||||
{
|
||||
this.BackgroundColor = ActiveTheme.Instance.SecondaryAccentColor;
|
||||
this.partLabel.TextColor = RGBA_Bytes.White;
|
||||
//this.partStatus.TextColor = RGBA_Bytes.White;
|
||||
this.viewButton.BackgroundColor = RGBA_Bytes.White;
|
||||
this.viewButtonLabel.TextColor = ActiveTheme.Instance.SecondaryAccentColor;
|
||||
}
|
||||
else if (this.IsSelected)
|
||||
{
|
||||
this.BackgroundColor = ActiveTheme.Instance.PrimaryAccentColor;
|
||||
this.partLabel.TextColor = RGBA_Bytes.White;
|
||||
//this.partStatus.TextColor = RGBA_Bytes.White;
|
||||
this.selectionCheckBox.TextColor = RGBA_Bytes.White;
|
||||
this.viewButton.BackgroundColor = RGBA_Bytes.White;
|
||||
this.viewButtonLabel.TextColor = ActiveTheme.Instance.SecondaryAccentColor;
|
||||
}
|
||||
else if (this.IsHoverItem)
|
||||
{
|
||||
this.BackgroundColor = RGBA_Bytes.White;
|
||||
this.partLabel.TextColor = RGBA_Bytes.Black;
|
||||
this.selectionCheckBox.TextColor = RGBA_Bytes.Black;
|
||||
//this.partStatus.TextColor = RGBA_Bytes.Black;
|
||||
this.viewButton.BackgroundColor = ActiveTheme.Instance.SecondaryAccentColor;
|
||||
this.viewButtonLabel.TextColor = RGBA_Bytes.White;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.BackgroundColor = new RGBA_Bytes(255, 255, 255, 255);
|
||||
this.partLabel.TextColor = RGBA_Bytes.Black;
|
||||
this.selectionCheckBox.TextColor = RGBA_Bytes.Black;
|
||||
//this.partStatus.TextColor = RGBA_Bytes.Black;
|
||||
this.viewButton.BackgroundColor = ActiveTheme.Instance.SecondaryAccentColor;
|
||||
this.viewButtonLabel.TextColor = RGBA_Bytes.White;
|
||||
}
|
||||
}
|
||||
|
||||
private SlideWidget getItemActionButtons()
|
||||
{
|
||||
var removeLabel = new TextWidget("Remove".Localize())
|
||||
{
|
||||
Name = "Queue Item " + listViewItem.Model.Name + " Remove",
|
||||
TextColor = RGBA_Bytes.White,
|
||||
VAnchor = VAnchor.ParentCenter,
|
||||
HAnchor = HAnchor.ParentCenter
|
||||
};
|
||||
|
||||
var removeButton = new FatFlatClickWidget(removeLabel)
|
||||
{
|
||||
VAnchor = VAnchor.ParentBottomTop,
|
||||
BackgroundColor = ActiveTheme.Instance.PrimaryAccentColor,
|
||||
Width = 100
|
||||
};
|
||||
removeButton.Click += onRemovePartClick;
|
||||
|
||||
viewButtonLabel = new TextWidget("View".Localize())
|
||||
{
|
||||
Name = "Queue Item " + listViewItem.Model.Name + " View",
|
||||
TextColor = RGBA_Bytes.White,
|
||||
VAnchor = VAnchor.ParentCenter,
|
||||
HAnchor = HAnchor.ParentCenter,
|
||||
};
|
||||
|
||||
viewButton = new FatFlatClickWidget(viewButtonLabel)
|
||||
{
|
||||
VAnchor = VAnchor.ParentBottomTop,
|
||||
BackgroundColor = ActiveTheme.Instance.SecondaryAccentColor,
|
||||
Width = 100,
|
||||
};
|
||||
viewButton.Click += onViewPartClick;
|
||||
|
||||
var buttonFlowContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
|
||||
{
|
||||
VAnchor = VAnchor.ParentBottomTop
|
||||
};
|
||||
buttonFlowContainer.AddChild(viewButton);
|
||||
buttonFlowContainer.AddChild(removeButton);
|
||||
|
||||
var buttonContainer = new SlideWidget()
|
||||
{
|
||||
VAnchor = VAnchor.ParentBottomTop,
|
||||
HAnchor = HAnchor.ParentRight
|
||||
};
|
||||
buttonContainer.AddChild(buttonFlowContainer);
|
||||
buttonContainer.Width = 200;
|
||||
|
||||
return buttonContainer;
|
||||
}
|
||||
|
||||
protected override async void UpdateHoverState()
|
||||
{
|
||||
if (!mouseInBounds)
|
||||
{
|
||||
IsHoverItem = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Hover only occurs after mouse is in bounds for a given period of time
|
||||
await Task.Delay(500);
|
||||
|
||||
if (!mouseInBounds)
|
||||
{
|
||||
IsHoverItem = false;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (UnderMouseState)
|
||||
{
|
||||
case UnderMouseState.NotUnderMouse:
|
||||
IsHoverItem = false;
|
||||
break;
|
||||
|
||||
case UnderMouseState.FirstUnderMouse:
|
||||
IsHoverItem = true;
|
||||
break;
|
||||
|
||||
case UnderMouseState.UnderMouseNotFirst:
|
||||
IsHoverItem = ContainsFirstUnderMouseRecursive();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onQueueItemClick(object sender, EventArgs e)
|
||||
{
|
||||
if (this.IsSelected)
|
||||
{
|
||||
this.IsSelected = false;
|
||||
this.selectionCheckBox.Checked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.IsSelected = true;
|
||||
this.selectionCheckBox.Checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void onRemovePartClick(object sender, EventArgs e)
|
||||
{
|
||||
this.actionButtonContainer.SlideOut();
|
||||
//UiThread.RunOnIdle(DeletePartFromQueue);
|
||||
}
|
||||
|
||||
private void onViewPartClick(object sender, EventArgs e)
|
||||
{
|
||||
this.actionButtonContainer.SlideOut();
|
||||
//UiThread.RunOnIdle(() =>
|
||||
//{
|
||||
// OpenPartViewWindow(View3DWidget.OpenMode.Viewing);
|
||||
//});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue