public KChartSKControl() : base() { chartControl = this; chartControl.Location = new Point(0, 0); Label toolTip = WinGui.winGui.label_Tooltip; toolTip.Visible = false; toolTip.BackColor = WinControls.cPanelButtonDeselected; toolTip.Font = WinGui.winGui.GetFont(8, true); toolTip.MouseEnter += (object sender, EventArgs e) => { UpdateTooltip(new Point(0, 0), ""); }; /* Initialize Interface KTouchClient with a locally-sourced KTouchClientData closure */ touch = new KTouchClientData( invalidateSurface: () => { InvalidateAndUpdate(); }, setManualPinchPan: (Swipe pinchPan) => { KChartHandler.SetManualPinchPan(pinchPan); } ); touch.onTouchSwipeOrMouseDrag = OnMouseDrag; touch.onTouchSwipeOrMouseDragEnd = OnMouseDragEnd; touch.onTouchDoubletapOrMouseClick = OnMouseClick; touch.onTouchPinchOrMouseZoom = OnMouseZoom; touch.lastPinchPan = Swipe.Id(); touch.incrementalScaling = Swipe.Id(); touch.incrementalTranslation = Swipe.Id(); KChartHandler.RegisterKTouchClientData(touch); }
public /* Interface KGuiControl */ void GuiChartData() { if (NSThread.IsMain) { // because of sandboxing, we must use the official Save Dialog to automatically create an exception and allow writing the file? var dlg = new NSSavePanel(); dlg.Title = "Save CSV File"; dlg.AllowedFileTypes = new string[] { "csv" }; dlg.Directory = MacControls.modelsDirectory; if (dlg.RunModal() == 1) { var path = ""; try { path = dlg.Url.Path; File.WriteAllText(path, KChartHandler.ToCSV(), System.Text.Encoding.Unicode); } catch { var alert = new NSAlert() { AlertStyle = NSAlertStyle.Critical, MessageText = "Could not write this file:", InformativeText = path }; alert.RunModal(); } } } else { _ = BeginInvokeOnMainThreadAsync(() => { GuiChartData(); return(ack); }).Result; } }
protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (DateTime.Now.Subtract(lastTooltipUpdate).TotalSeconds > 0.01) { KChartHandler.ShowEndNames(!shiftKeyDown); if (mouseDown) { UpdateTooltip(new Point(0, 0), ""); } else if (!shiftKeyDown) { UpdateTooltip(new Point(e.X, e.Y), KChartHandler.HitListTooltip(Swipe.Inverse(new SKPoint(e.X, e.Y), KChartHandler.GetManualPinchPan()), 10)); } lastTooltipUpdate = DateTime.Now; if (!KControls.IsSimulating()) { Invalidate(); // because of ShowEndNames } } if (mouseDown) { touch.onTouchSwipeOrMouseDrag?.Invoke(mouseDownPoint, new SKPoint(e.Location.X, e.Location.Y)); } }
private void OnPaintCanvas(object sender, SKPaintSurfaceEventArgs e) { SKChartPainter painter = new SKChartPainter(e.Surface.Canvas); KChartHandler.Draw(painter, 0, 0, e.Info.Width, e.Info.Height); data.DisplayTouchLocation(painter); }
public bool MyModifiersChanged(NSEvent e) { if (e.ModifierFlags.HasFlag(NSEventModifierMask.ShiftKeyMask)) //0x38 kVK_Shift { shiftKeyDown = true; if (mouseInsideChartControl) { KChartHandler.ShowEndNames(false); showTooltip = false; UpdateTooltip(e); if (!KControls.IsSimulating()) { Invalidate(); } } return(true); } else { shiftKeyDown = false; if (mouseInsideChartControl) { KChartHandler.ShowEndNames(true); showTooltip = true; UpdateTooltip(e); if (!KControls.IsSimulating()) { Invalidate(); } } return(false); } }
// Implement this to draw on the canvas. public override void DrawRect(CGRect dirtyRect) { base.DrawRect(dirtyRect); var context = NSGraphicsContext.CurrentContext.CGContext; CG.FlipCoordinateSystem(context); KChartHandler.Draw(new CGChartPainter(context), (int)dirtyRect.X, (int)dirtyRect.Y, (int)dirtyRect.Width, (int)dirtyRect.Height); }
protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); mouseInsideChartControl = true; KChartHandler.ShowEndNames(true); if (!KControls.IsSimulating()) { Invalidate(); } }
// ======== On Switched To ========= // public override void OnSwitchedTo() { MainTabbedPage.OnAnySwitchedTo(this); MainTabbedPage.theModelEntryPage.SyncNoisePicker(noisePicker); if (!Exec.IsExecuting() && // we could be waiting on a continuation! StartAction would switch us right back to this page even if it does not start a thread! currentModelInfo != MainTabbedPage.theModelEntryPage.modelInfo) // forkWorker: we can compute the chart concurrently { MainTabbedPage.theModelEntryPage.StartAction(forkWorker: true, switchToChart: false, switchToOutput: false, autoContinue: false); } KChartHandler.ChartUpdate(null); }
public override void MouseExited(NSEvent e) { base.MouseExited(e); mouseInsideChartControl = false; showTooltip = false; UpdateTooltip(e); KChartHandler.ShowEndNames(false); if (!KControls.IsSimulating()) { Invalidate(); } }
public override void MouseEntered(NSEvent e) { base.MouseEntered(e); mouseInsideChartControl = true; showTooltip = !shiftKeyDown; KChartHandler.ShowEndNames(!shiftKeyDown); if (!KControls.IsSimulating()) { Invalidate(); } }
protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); mouseInsideChartControl = false; UpdateTooltip(new Point(0, 0), ""); KChartHandler.ShowEndNames(false); if (!KControls.IsSimulating()) { Invalidate(); } }
public /* Interface KGuiControl */ void GuiChartUpdate() { if (NSThread.IsMain) { KChartHandler.VisibilityRestore(); // this is needed to hide the series in the chart this.kaemikaChart.Invalidate(); } else { _ = BeginInvokeOnMainThreadAsync(() => { GuiChartUpdate(); return(ack); }).Result; } }
public static void OnShiftKeyUp() // called from GuiToWin.GuiToWin_KeyUp form callback { shiftKeyDown = false; if (mouseInsideChartControl) { KChartHandler.ShowEndNames(true); if (!KControls.IsSimulating()) { chartControl.Invalidate(); } } }
public /* Interface KGuiControl */ void GuiLegendUpdate() { if (NSThread.IsMain) { KChartHandler.VisibilityRestore(); // this is needed to hide the series in the legend KGui.kControls.SetLegend(); } else { _ = BeginInvokeOnMainThreadAsync(() => { GuiLegendUpdate(); return(ack); }).Result; } }
public /* Interface KGuiControl */ void GuiLegendUpdate() { if (!this.InvokeRequired) { KChartHandler.VisibilityRestore(); // this is needed to hide the series in the legend KGui.kControls.SetLegend(); KGui.kControls.InvalidateLegend(); } else { this.Invoke((Action) delegate { GuiLegendUpdate(); }); } }
public static bool shiftKeyDown = false; // See also WinGui_KeyDown, WinGui_KeyUp public static void OnShiftKeyDown() // called from GuiToWin.GuiToWin_KeyDown form callback { shiftKeyDown = true; if (mouseInsideChartControl) { KChartHandler.ShowEndNames(false); chartControl.UpdateTooltip(new Point(0, 0), ""); if (!KControls.IsSimulating()) { chartControl.Invalidate(); } } }
public /* Interface KGuiControl */ void GuiChartUpdate() { if (!this.InvokeRequired) { KChartHandler.VisibilityRestore(); // this is needed to hide the series in the chart KChartSKControl.SetSize(panel_KChart.Size); KChartSKControl.InvalidateAndUpdate(); } else { this.Invoke((Action) delegate { GuiChartUpdate(); }); } }
public static (string[] series, string[] seriesLNA) GenerateSeries(List <ReportEntry> reports, Noise noise, Style style) { if (!style.chartOutput) { return(null, null); } string[] seriesLNA = new string[reports.Count]; // can contain nulls if series are duplicates paletteNo = (reports.Count - 1) % palette.Length; // because we scan palette backwards for (int i = reports.Count - 1; i >= 0; i--) // add series backwards so that Red is in front // generate LNA-dependent series { ReportEntry entry = reports[i]; bool noisePlottable = (noise != Noise.None) && entry.flow.HasStochasticVariance() && !entry.flow.HasNullVariance(); if (noisePlottable) { string reportName = (entry.asLabel != null) ? entry.asLabel : entry.flow.TopFormat(style.RestyleAsNumberFormat("G4")); string seriesName = reportName + Gui.StringOfNoise(noise); seriesLNA[i] = KChartHandler.ChartAddSeries(seriesName, entry.flow, palette[paletteNo % palette.Length], noise); // could be null } paletteNo--; if (paletteNo < 0) { paletteNo += palette.Length; // decrement out here to keep colors coordinated } } string[] series = new string[reports.Count]; // can contain nulls if series are duplicates paletteNo = (reports.Count - 1) % palette.Length; // because we scan palette backwards for (int i = reports.Count - 1; i >= 0; i--) // add series backwards so that Red is in front // generate deterministic series { ReportEntry entry = reports[i]; bool meanPlottable = (noise == Noise.None && entry.flow.HasDeterministicValue()) || ((noise != Noise.None) && entry.flow.HasStochasticMean()); bool noisePlottable = (noise != Noise.None) && entry.flow.HasStochasticVariance() && !entry.flow.HasNullVariance(); if (meanPlottable) { string reportName = (entry.asLabel != null) ? entry.asLabel : entry.flow.TopFormat(style.RestyleAsNumberFormat("G4")); string seriesName = reportName + (noisePlottable ? Gui.StringOfNoise(Noise.None) : ""); // do postfix mu if there is no sigma plot for it //string seriesName = reportName + ((noise == Noise.None) ? "" : Gui.StringOfNoise(Noise.None)); // previous version series[i] = KChartHandler.ChartAddSeries(seriesName, entry.flow, palette[paletteNo % palette.Length], Noise.None); // could be null } paletteNo--; if (paletteNo < 0) { paletteNo += palette.Length; // decrement out here to keep colors coordinated } } return(series, seriesLNA); }
private void UpdateTooltip(NSEvent e) { (CGPoint native, SKPoint flipped) = ConvertToCanvasPoint(e); flipped = Swipe.Inverse(flipped, KChartHandler.GetManualPinchPan()); // adjust for current pinchPan string tip = (showTooltip) ? KChartHandler.HitListTooltip(flipped, 10) : ""; if (tip == "") { MacGui.macGui.SetChartTooltip("", new CGPoint(0, 0), new CGRect(0, 0, 0, 0)); } else { MacGui.macGui.SetChartTooltip(tip, native, Frame); } }
public void SetLegend() // Called by LegendUpdate { KSeries[] legend = KChartHandler.Legend(); guiControls.menuLegend.ClearMenuItems(); for (int i = legend.Length - 1; i >= 0; i--) { KSeries series = legend[i]; // captured in the OnClick closure series.lineButton = guiControls.menuLegend.NewMenuSection(); series.lineButton.SetLegendImage(series); series.lineButton.OnClick((object s, EventArgs e) => { OnLegendClick(legend, series); }); series.nameButton = guiControls.menuLegend.NewMenuItemButton(); series.nameButton.SetText(series.name); series.nameButton.OnClick((object s, EventArgs e) => { OnLegendClick(legend, series); }); guiControls.menuLegend.AddMenuRow(new KButton[2] { series.lineButton, series.nameButton }); //, pad }); } guiControls.menuLegend.Open(); }
public void OnLegendClick(KSeries[] legend, KSeries series) { if (guiControls.IsShiftDown()) { KChartHandler.ShiftInvertVisible(series.name); foreach (var seriesI in legend) { seriesI.lineButton.SetLegendImage(seriesI); } } else { KChartHandler.InvertVisible(series.name); series.lineButton.SetLegendImage(series); // accessing the shared series data structure! } KChartHandler.VisibilityRemember(); KChartHandler.ChartUpdate(null); // cannot provide style: would have to marshall it throug KGui but is ok to update }
public override void MouseMoved(NSEvent e) { base.MouseMoved(e); if (!mouseInsideChartControl) { return; } (CGPoint native, SKPoint location) = ConvertToCanvasPoint(e); lastLocationForZoom = location; if (DateTime.Now.Subtract(lastTooltipUpdate).TotalSeconds > 0.01) { KChartHandler.ShowEndNames(!shiftKeyDown); showTooltip = !shiftKeyDown; UpdateTooltip(e); lastTooltipUpdate = DateTime.Now; if (!KControls.IsSimulating()) { Invalidate(); // because of ShowEndNames } } }
const int LegendItemHeight = 21; // If this value is too small (for the font size?), Label items will flash a gray box for 2 senconds when updated public void SetLegend() { KSeries[] legend = KChartHandler.Legend(); Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { var legendList = new ObservableCollection <LegendItem>(); for (int i = legend.Length - 1; i >= 0; i--) { legendList.Add(new LegendItem { Name = legend[i].name, Color = SkiaSharp.Views.Forms.Extensions.ToFormsColor(legend[i].color), Width = (legend[i].visible) ? 50 : 6, Height = (legend[i].lineStyle == KLineStyle.Thick) ? 4 // show a wide bar for thick plot lines : (legend[i].lineMode == KLineMode.Line) ? 1 // show a smaller bar for think plot lines : LegendItemHeight, // show a full rectangle for Range areas }); } legendView.ItemsSource = legendList; MainTabbedPage.theChartPage.inspectionView.Children[0].HeightRequest = 40 + LegendItemHeight * (legend.Length + 1) / 2; // seems redundant? }); }
private KTouchClientData touch = null; // data for pan&zoom by mouse drag and scroll private void OnLoad() { this.WantsLayer = true; this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay; chartControl = this; /* Initialize Interface KTouchClient with a locally-sourced KTouchClientData closure */ touch = new KTouchClientData( invalidateSurface: () => { Invalidate(); }, setManualPinchPan: (Swipe pinchPan) => { KChartHandler.SetManualPinchPan(pinchPan); } ); touch.onTouchSwipeOrMouseDrag = OnMouseDrag; touch.onTouchSwipeOrMouseDragEnd = OnMouseDragEnd; touch.onTouchDoubletapOrMouseClick = OnMouseClick; touch.onTouchPinchOrMouseZoom = OnMouseZoom; touch.lastPinchPan = Swipe.Id(); touch.incrementalScaling = Swipe.Id(); touch.incrementalTranslation = Swipe.Id(); KChartHandler.RegisterKTouchClientData(touch); Tracking(); }
public /* Interface KGuiControl */ void GuiChartData() { if (!this.InvokeRequired) { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "CSV files (*.csv)|*.csv|All files (*.*)|*.*"; saveFileDialog.InitialDirectory = WinControls.modelsDirectory; saveFileDialog.FilterIndex = 1; saveFileDialog.RestoreDirectory = false; if (saveFileDialog.ShowDialog() == DialogResult.OK) { try { File.WriteAllText(saveFileDialog.FileName, KChartHandler.ToCSV(), System.Text.Encoding.Unicode); } catch { MessageBox.Show(saveFileDialog.FileName, "Could not write this file:", MessageBoxButtons.OK); } } } else { this.Invoke((Action) delegate { GuiChartData(); }); } }
private static IEnumerable <SolPoint> SolutionGererator( Func <double, double, Vector, Func <double, Vector, Vector>, IEnumerable <SolPoint> > Solver, State initialState, double initialTime, double finalTime, Func <double, Vector, Vector> Flux, bool nonTrivialSolution, Style style) { IEnumerable <SolPoint> solution; if (nonTrivialSolution) { try { IEnumerable <SolPoint> solver = Solver(initialTime, finalTime, initialState.ToArray(), Flux); solution = OdeHelpers.SolveTo(solver, finalTime); } catch (Error e) { throw new Error(e.Message); } catch (Exception e) { KChartHandler.ChartUpdate(style, false); throw new Error("ODE Solver FAILED: " + e.Message); } } else // build a dummy point series, in case we want to report and plot just some numerical expressions { List <SolPoint> list = new List <SolPoint> { }; // SolPoint constructor was changed to public from internal if (finalTime <= initialTime) { list.Add(new SolPoint(initialTime, initialState.ToArray())); } else { for (double t = initialTime; t <= finalTime; t += ((finalTime - initialTime) / 1000.0)) { list.Add(new SolPoint(t, initialState.ToArray())); } } solution = list; } return(solution); }
public ChartView() { // register this as KTouchable so that touch callbacks can be attached through interface KTouchable: // (Register it if we want to add special actions for mouse or touch, beyond the built-in two-finger swiping and zooming that changes the global KChart.pinchPan, which is automatically handled by KTouch for all platforms) // KChartHandler.Register(this); // ###################### // HeightRequest = 300; this.BackgroundColor = Color.White; this.PaintSurface += OnPaintCanvas; /* Attact Touch effect from KTouch.OnTouchEffectAction */ TouchEffect touchEffect = new TouchEffect(); touchEffect.TouchAction += KTouchServer.OnTouchEffectAction; touchEffect.Capture = true; // "This has the effect of delivering all subsequent events to the same event handler" this.Effects.Add(touchEffect); /* Initialize Interface KTouchClient with a locally-sourced KTouchClientData closure */ this.data = new KTouchClientData( invalidateSurface: () => { this.InvalidateSurface(); }, setManualPinchPan: (Swipe pinchPan) => { KChartHandler.SetManualPinchPan(pinchPan); } ); KChartHandler.RegisterKTouchClientData(data); }
public CollectionView LegendView() { CollectionView collectionView = new CollectionView() { //ItemsLayout = ListItemsLayout.VerticalList, // can also be set to a vertical grid ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical), SelectionMode = SelectionMode.Single, }; // collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys"); // a binding for the ItemSource, but we give keep regenerating it collectionView.ItemsSource = new ObservableCollection <LegendItem>(); // CollectionView contains LegendItems with bindings set in ItemTemplate collectionView.ItemTemplate = new DataTemplate(() => { // CollectionView contains LegendItems with bindings set in ItemTemplate Grid grid = new Grid { Padding = 2 }; grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(LegendItemHeight) }); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); // grid.ColumnDefinitions.Add(new ColumnDefinition { Width = 50 }); //it is definitely labels that flash a gray box when updated BoxView box = new BoxView { VerticalOptions = LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center }; // needed, otherwise the default .Fill option ignores HeightRequest box.SetBinding(BoxView.ColorProperty, "Color"); // property of LegendItem box.SetBinding(BoxView.HeightRequestProperty, "Height"); // property of LegendItem box.SetBinding(BoxView.WidthRequestProperty, "Width"); // property of LegendItem Label nameLabel = new Label { FontSize = LegendFontSize, FontAttributes = FontAttributes.Bold }; nameLabel.SetBinding(Label.TextProperty, "Name"); // property of LegendItem grid.Children.Add(box, 0, 0); grid.Children.Add(nameLabel, 1, 0); // grid.Children.Add(new Label { Text = "xxx" }, 2, 0); //it is definitely labels that flash a gray box when updated return(grid); }); collectionView.SelectionChanged += (object sender, SelectionChangedEventArgs args) => { LegendItem item = collectionView.SelectedItem as LegendItem; if (item != null) { KChartHandler.InvertVisible(item.Name); KChartHandler.VisibilityRemember(); KChartHandler.ChartUpdate(null); KGui.gui.GuiLegendUpdate(); collectionView.SelectedItem = null; // avoid some visible flashing of the selection } }; return(collectionView); }
// Implement this to draw on the canvas. protected override void OnPaintSurface(SkiaSharp.Views.Desktop.SKPaintSurfaceEventArgs e) { base.OnPaintSurface(e); KChartHandler.Draw(new SKChartPainter(e.Surface.Canvas), Location.X, Location.Y, e.Info.Width, e.Info.Height); }
private static void Execute_Worker(bool doParse, bool doAST, bool doScope, bool autoContinue, bool chartOutput) { KGui.gui.GuiBeginningExecution(); lastExecution = null; KGui.gui.GuiSaveInput(); KGui.gui.GuiOutputClear(); DateTime startTime = DateTime.Now; if (TheParser.Parser().Parse(KGui.gui.GuiInputGetText(), out IReduction root)) { if (doParse) { root.DrawReductionTree(); } else { Netlist netlist = new Netlist(autoContinue); try { Statements statements = Parser.ParseTop(root); if (doAST) { KGui.gui.GuiOutputAppendText(statements.Format()); } else { SampleValue vessel = Vessel(KControls.SelectNoiseSelectedItem != Noise.None); Env initialEnv = new ValueEnv("vessel", Type.Sample, vessel, new BuiltinEnv(new NullEnv())); Scope initialScope = initialEnv.ToScope(); Scope scope = statements.Scope(initialScope); if (doScope) { KGui.gui.GuiOutputAppendText(scope.Format()); } else { Style style = new Style(varchar: scopeVariants ? defaultVarchar : null, new SwapMap(), map: remapVariants ? new AlphaMap() : null, numberFormat: "G4", dataFormat: "full", // we want it full for samples, but maybe only headers for functions/networks? exportTarget: ExportTarget.Standard, traceFull: false, chartOutput: chartOutput); KChartHandler.ChartClear("", "s", "M", style); KChartHandler.LegendUpdate(style); KScoreHandler.ScoreClear(); KControls.ParametersClear(style); KDeviceHandler.Clear(style); KDeviceHandler.Sample(vessel, style); netlist.Emit(new SampleEntry(vessel)); DateTime evalTime = DateTime.Now; lastExecution = new ExecutionInstance(vessel, netlist, style, startTime, evalTime); lastExecution.environment = statements.EvalReject(initialEnv, netlist, style, 0); if (lastExecution.environment == null) { throw new Error("Top level reject"); } lastExecution.EndTime(); if (style.chartOutput) { foreach (ParameterEntry parameter in netlist.Parameters()) { KControls.AddParameter(parameter.symbol.Format(style), (parameter.value as NumberValue).value, parameter.distribution, style); } KGui.gui.GuiParametersUpdate(); // calls back KControls.ParametersUpdate, but only on Win/Mac } KGui.gui.GuiProcessOutput(); } } } catch (ExecutionEnded) { lastExecution.EndTime(); KGui.gui.GuiOutputAppendText(lastExecution.ElapsedTime()); } catch (ConstantEvaluation ex) { string cat = "Does not have a value: "; netlist.Emit(new CommentEntry(cat + ": " + ex.Message)); KGui.gui.GuiInputSetErrorSelection(-1, -1, 0, cat, ex.Message); } catch (Error ex) { netlist.Emit(new CommentEntry(ex.Message)); KGui.gui.GuiInputSetErrorSelection(-1, -1, 0, "Error", ex.Message); try { KGui.gui.GuiProcessOutput(); } catch { }; } catch (StackOverflowException ex) { netlist.Emit(new CommentEntry(ex.Message)); KGui.gui.GuiInputSetErrorSelection(-1, -1, 0, "Stack Overflow", ex.Message); } catch (Exception ex) { string cat = "Something happened"; netlist.Emit(new CommentEntry(cat + ": " + ex.Message)); KGui.gui.GuiInputSetErrorSelection(-1, -1, 0, cat, ex.Message); } } } else { KGui.gui.GuiInputSetErrorSelection(TheParser.Parser().FailLineNumber(), TheParser.Parser().FailColumnNumber(), TheParser.Parser().FailLength(), TheParser.Parser().FailCategory(), TheParser.Parser().FailMessage()); } EndingExecution(); }