public ApplicationContent( IApp page = null, IApplicationWebServiceX service = null) { // need absolute path when docked.. page.style1.href = page.style1.href; // first order of business. // enable drop zone. var dz = new DropZone(); dz.Container.AttachToDocument(); dz.Container.Hide(); var StayAlertTimer = default(Timer); var DoRefresh = default(Action); #region StayAlert Action<string> StayAlert = transaction_id => { StayAlertTimer = new Timer( delegate { service.GetTransactionKeyAsync( id => { if (id == transaction_id) return; // shot down during flight? if (!StayAlertTimer.IsAlive) return; Console.WriteLine("StayAlert " + new { id, transaction_id }); DoRefresh(); } ); } ); StayAlertTimer.StartInterval(5000); }; #endregion DoRefresh = delegate { if (StayAlertTimer != null) StayAlertTimer.Stop(); page.output.Clear(); new FileLoading().Container.AttachTo(page.output); service.EnumerateFilesAsync( y: ( long ContentKey, string ContentValue, string ContentType, long ContentBytesLength ) => { var e = new FileEntry(); #region ContentValue e.ContentValue.value = ContentValue.TakeUntilLastIfAny("."); e.ContentValue.onchange += delegate { var ext = ContentValue.SkipUntilLastOrEmpty("."); if (ext != "") ext = "." + ext; ContentValue = e.ContentValue.value + ext; Console.WriteLine("before update!"); service.UpdateAsync( ContentKey, ContentValue, // null does not really work? delegate { Console.WriteLine("update done!"); } ); e.open.href = Native.Document.location.href.TakeUntilLastIfAny("/") + "/io/" + ContentKey + "/" + ContentValue; }; e.open.href = Native.Document.location.href.TakeUntilLastIfAny("/") + "/io/" + ContentKey + "/" + ContentValue; e.open.target = Target; #endregion e.ContentType.innerText = ContentBytesLength + " bytes " + ContentType; #region Delete e.Delete.WhenClicked( delegate { //e.ContentValue.style.textDecoration = "" if (StayAlertTimer != null) StayAlertTimer.Stop(); e.Container.style.backgroundColor = "red"; service.DeleteAsync( ContentKey, delegate { DoRefresh(); } ); } ); #endregion e.Container.AttachTo(page.output); Console.WriteLine( new { ContentKey, ContentValue, ContentType, ContentBytesLength } ); }, done: transaction_id => { Console.WriteLine(new { transaction_id }); new FileLoadingDone().Container.AttachTo(page.output); StayAlert(transaction_id); } ); }; #region ondrop var TimerHide = new Timer( delegate { dz.Container.Hide(); } ); Action<DragEvent> ondragover = evt => { //Console.WriteLine("ondragover"); evt.stopPropagation(); evt.preventDefault(); // ondragover { type = Files } //foreach (var type in evt.dataTransfer.types) //{ // Console.WriteLine("ondragover " + new { type }); //} if (evt.dataTransfer.types.Contains("Files")) { evt.dataTransfer.dropEffect = "copy"; // Explicitly show this is a copy. dz.Container.Show(); TimerHide.Stop(); } //} //Console.WriteLine(" Native.Document.body.ondragover"); }; Native.Document.body.ondragover += ondragover; dz.Container.ondragover += ondragover; //dz.Container.ondragstart += // evt => // { // Console.WriteLine("ondragstart"); // evt.stopPropagation(); // evt.preventDefault(); // }; dz.Container.ondragleave += evt => { //Console.WriteLine("ondragleave"); //Console.WriteLine(" dz.Container.ondragleave"); evt.stopPropagation(); evt.preventDefault(); TimerHide.StartTimeout(90); }; dz.Container.ondrop += evt => { //Console.WriteLine("ondrop"); TimerHide.StartTimeout(90); evt.stopPropagation(); evt.stopImmediatePropagation(); evt.preventDefault(); // can we use a webClient yet? var xhr = new IXMLHttpRequest(); // does not work for chrome? //xhr.setRequestHeader("WebServiceMethod", "FileStorageUpload"); // which server? xhr.open(ScriptCoreLib.Shared.HTTPMethodEnum.POST, "/FileStorageUpload"); // http://stackoverflow.com/questions/13870853/how-to-upload-files-in-web-workers-when-formdata-is-not-defined //var c = new WebClient(); ////c.UploadData( //c.UploadProgressChanged += // (sender, args) => // { // }; //c.UploadFileAsync( #region send var d = new FormData(); evt.dataTransfer.files.AsEnumerable().WithEachIndex( (f, index) => { d.append("file" + index, f, f.name); } ); xhr.InvokeOnComplete( delegate { Console.WriteLine("upload complete!"); DoRefresh(); } ); var upload = new Uploading(); upload.Container.AttachTo(page.output); // http://www.matlus.com/html5-file-upload-with-progress/ xhr.upload.onprogress += e => { var p = (int)(e.loaded * 100 / e.total) + "%"; upload.status = p; Console.WriteLine("upload.onprogress " + new { e.total, e.loaded }); }; xhr.send(d); #endregion if (StayAlertTimer != null) StayAlertTimer.Stop(); }; #endregion DoRefresh(); }
/// <summary> /// Creates a new control /// </summary> /// <param name="DataElement">The hidden data element</param> public LightsOut2(IHTMLElement DataElement) { // based on http://www.cjcraft.com/Blog/PermaLink,guid,5c35b1f1-dc66-4d85-ac04-22fc97503d4a.aspx // what happens in beta2 when the anonymous types are immutable? :) var usersettings = new { x = 5, y = 5, tile = new { w = 64, h = 64, cold = 0.8 } }; var a = new Array2D<IHTMLDiv>(usersettings.x, usersettings.y); var m = a.ToBooleanArray(); var r = new System.Random(); m.ForEach( (x, y) => { m[x, y] = r.NextDouble() > 0.5; } ); var canvas = new IHTMLDiv(); canvas.className = "canvas"; var canvas_size = new __Type1 { x = ((a.XLength + 1) * usersettings.tile.w), y = ((a.YLength + 1) * usersettings.tile.h) }; canvas.style.position = IStyle.PositionEnum.relative; canvas.style.border = "2px solid black"; canvas.style.width = canvas_size.x + "px"; canvas.style.height = canvas_size.y + "px"; var canvas_bg = new IHTMLDiv(); //var canvas_bg_tween = new TweenDataDouble(); //canvas_bg_tween.Value = 1; //canvas_bg_tween.ValueChanged += delegate { canvas_bg.style.Opacity = canvas_bg_tween.Value; }; new HTML.Images.FromAssets.background().ToBackground(canvas_bg.style); //canvas_bg.style.backgroundImage = Assets.Default.Background.StyleSheetURL; canvas_bg.style.SetLocation(0, 0, canvas_size.x * 2, canvas_size.y); canvas.appendChild(canvas_bg); IStyleSheet.Default.AddRule(".info").style .Aggregate(s => { s.backgroundColor = Color.Black; s.color = Color.White; s.padding = "2em"; s.fontFamily = IStyle.FontFamilyEnum.Tahoma; s.Float = IStyle.FloatEnum.right; }) ; IStyleSheet.Default.AddRule(".canvas").style .Aggregate(s => s.overflow = IStyle.OverflowEnum.hidden) .Aggregate(s => s.backgroundColor = Color.Black) ; IStyleSheet.Default.AddRule(".on").style .Aggregate(s => new HTML.Images.FromAssets.vistaLogoOn().ToBackground(s) ) //.Aggregate(s => s.Opacity = 0.8) ; IStyleSheet.Default.AddRule(".off").style .Aggregate(s => new HTML.Images.FromAssets.vistaLogoOff().ToBackground(s) ) //.Aggregate(s => s.Opacity = 0.5) ; Action<int, int> UpdateColor = (x, y) => { var n = a[x, y]; if (m[x, y]) { n.className = "on"; } else { n.className = "off"; } }; Action<int, int> ToggleDirect = (x, y) => { var n = a[x, y]; if (n == null) return; m[x, y] = !m[x, y]; UpdateColor(x, y); }; Action<int, int> Toggle = (x, y) => { //Console.WriteLine("click at: " + new { x, y } + " = " + m[x, y]); var f = ToggleDirect.WithOffset(x, y); f(-1, 0); f(0, -1); f(0, 0); f(0, 1); f(1, 0); }; var info_stats_clicks = new IHTMLDiv(); var info_stats_clicks_count = 0; var info_stats_off = new IHTMLDiv(); var info_stats_on = new IHTMLDiv(); Action info_stats_update = () => { info_stats_clicks.innerHTML = info_stats_clicks_count + " clicks made so far"; info_stats_on.innerHTML = m.Count(i => i) + " blocks are on"; info_stats_off.innerHTML = m.Count(i => !i) + " blocks are off"; }; var info_stats = new IHTMLDiv(info_stats_clicks, info_stats_off, info_stats_on); info_stats.className = "info"; a.ForEach( (x, y) => { var n = new IHTMLDiv(); n.style.left = (x * usersettings.tile.w + usersettings.tile.w / 2) + "px"; n.style.top = (y * usersettings.tile.h + usersettings.tile.h / 2) + "px"; n.style.width = usersettings.tile.w + "px"; n.style.height = usersettings.tile.h + "px"; n.style.position = IStyle.PositionEnum.absolute; n.style.overflow = IStyle.OverflowEnum.hidden; //n.style.border = "1px solid black"; n.style.cursor = IStyle.CursorEnum.pointer; canvas.appendChild(n); var tween = new TweenDataDouble(); tween.ValueChanged += () => n.style.Opacity = tween.Value; tween.Value = usersettings.tile.cold; n.style.Opacity = tween.Value; n.onmouseover += delegate { tween.Value = 1; //canvas_bg_tween.Value = 0.5; }; n.onmouseout += delegate { tween.Value = usersettings.tile.cold; //canvas_bg_tween.Value = 1; }; n.onclick += delegate { info_stats_clicks_count++; Toggle(x, y); info_stats_update(); }; a[x, y] = n; UpdateColor(x, y); } ); var ani = new Timer(t => canvas_bg.style.left = -(int)System.Math.Floor((double)((IDate.Now.getTime() / 75) % canvas_size.x)) + "px"); var info = new IHTMLDiv(); var info_header_text = "Lights out 2"; Native.Document.title = info_header_text; info.appendChild(new IHTMLElement(IHTMLElement.HTMLElementEnum.h1, info_header_text)); info.appendChild(new IHTMLAnchor("http://www.cjcraft.com/Blog/PermaLink,guid,5c35b1f1-dc66-4d85-ac04-22fc97503d4a.aspx", "based on SilverlightsOut")); info.appendChild(new IHTMLBreak()); info.appendChild(new IHTMLAnchor("http://www.cjcraft.com/Blog/CommentView,guid,5c35b1f1-dc66-4d85-ac04-22fc97503d4a.aspx", "cjcraft blog post")); info.appendChild(new IHTMLElement(IHTMLElement.HTMLElementEnum.p, @"Lights out is a one player puzzle that is played on a 5 by 5 grid of squares in which every square has two states: on and off. The game starts off with all squares off, where the goal is to turn on every square. By selecting a square, all the surrounding squares' (up, down, left, right) state is turned toggled. For example, on a 3 by 3 grid of squares with all squares off, if the center one is selected, it will turn 'on' the 4 up, down, left, right squares from it.")); info.appendChild(new IHTMLDiv("Mozilla based browsers seem to suffer in performance while animating contents under semitransparent elements.")); info.appendChild(new IHTMLButton("Animate background").Aggregate(btn => btn.onclick += delegate { ani.StartInterval(50); })); info.appendChild(new IHTMLButton("Freeze background").Aggregate(btn => btn.onclick += delegate { ani.Stop(); })); info.appendChild(info_stats); info.appendChild(canvas); info_stats_update(); DataElement.insertNextSibling(info); }
/// <summary> /// This is a javascript application. /// </summary> /// <param name="page">HTML document rendered by the web server which can now be enhanced.</param> public Application(IDefaultPage page) { var SpiderModelContent = new SpiderModel.ApplicationContent(); page.program_13_turn_left.onclick += delegate { SpiderModelContent.po = 13; }; page.program_14_turn_right.onclick += delegate { SpiderModelContent.po = 14; }; page.program_15_go_backwards.onclick += delegate { SpiderModelContent.po = 15; }; page.program_16_go_forwards.onclick += delegate { SpiderModelContent.po = 16; }; page.program_53_mayday.onclick += delegate { SpiderModelContent.po = 53; }; page.program_43_high_five_calibration_stand.onclick += delegate { SpiderModelContent.po = 43; }; page.stop.onclick += delegate { SpiderModelContent.po = 0; ; }; new Timer( tttt => { var pp = SpiderModelContent.pp; if (tttt.Counter % 2 == 0) pp = 0; if (pp == 13) page.program_13_turn_left.style.color = JSColor.Blue; else page.program_13_turn_left.style.color = JSColor.None; if (pp == 14) page.program_14_turn_right.style.color = JSColor.Blue; else page.program_14_turn_right.style.color = JSColor.None; if (pp== 15) page.program_15_go_backwards.style.color = JSColor.Blue; else page.program_15_go_backwards.style.color = JSColor.None; if (pp == 16) page.program_16_go_forwards.style.color = JSColor.Blue; else page.program_16_go_forwards.style.color = JSColor.None; }, 300, 150 ); #region program_60 page.program_60.onclick += delegate { #region po Action<int> po = v => { page.program_60.innerText = "program_60: " + v; SpiderModelContent.po = v; }; #endregion #region po_to_po Action<int, int> po_to_po = (from, to) => { if (SpiderModelContent.po != from) return; po(to); }; #endregion #region po_to_po_at Action<int, int, int> po_to_po_at = (from, to, xdelay) => { new Timer(delegate { po_to_po(from, to); }, xdelay * 1000, 0); }; #endregion // turn left until 3 po(13); // wait 3 sec and go backwards until 6 po_to_po_at(13, 15, 3); // wait 6 sec and turn right po_to_po_at(15, 14, 3 + 6); // wait 6 sec and go forwards until 6 po_to_po_at(14, 16, 3 + 6 + 6); // wait 3 sec and stop po_to_po_at(16, 0, 3 + 6 + 6 + 6); }; #endregion #region program_61 page.program_61.onclick += delegate { #region po Action<int> po = v => { page.program_61.innerText = "program_61: " + v; SpiderModelContent.po = v; }; #endregion #region po_to_po Action<int, int> po_to_po = (from, to) => { if (SpiderModelContent.po != from) return; po(to); }; #endregion #region po_to_po_at Action<int, int, int> po_to_po_at = (from, to, xdelay) => { new Timer(delegate { po_to_po(from, to); }, xdelay * 1000, 0); }; #endregion // turn left until 3 po(14); // wait 3 sec and go backwards until 6 po_to_po_at(14, 15, 3); // wait 6 sec and turn right po_to_po_at(15, 13, 3 + 6); // wait 6 sec and go forwards until 6 po_to_po_at(13, 16, 3 + 6 + 6); // wait 3 sec and stop po_to_po_at(16, 0, 3 + 6 + 6 + 6); }; #endregion @"Hello world".ToDocumentTitle(); #region sidebars var LeftLR = new IHTMLDiv(); LeftLR.style.position = IStyle.PositionEnum.absolute; LeftLR.style.left = "0"; LeftLR.style.top = "0"; LeftLR.style.bottom = "0"; LeftLR.style.width = "4em"; LeftLR.style.Opacity = 0.5; LeftLR.AttachToDocument(); var LeftIR = new IHTMLDiv(); LeftIR.style.position = IStyle.PositionEnum.absolute; LeftIR.style.left = "0"; LeftIR.style.top = "0"; LeftIR.style.height = "1em"; LeftIR.style.width = "4em"; LeftIR.style.Opacity = 0.8; LeftIR.AttachToDocument(); LeftIR.style.backgroundColor = JSColor.FromRGB(0xB0, 0, 0); var RightLR = new IHTMLDiv(); RightLR.style.position = IStyle.PositionEnum.absolute; RightLR.style.right = "0"; RightLR.style.top = "0"; RightLR.style.bottom = "0"; RightLR.style.Opacity = 0.5; RightLR.style.width = "4em"; RightLR.AttachToDocument(); var RightIR = new IHTMLDiv(); RightIR.style.position = IStyle.PositionEnum.absolute; RightIR.style.right = "0"; RightIR.style.top = "0"; RightIR.style.height = "1em"; RightIR.style.width = "4em"; RightIR.style.Opacity = 0.8; RightIR.AttachToDocument(); RightIR.style.backgroundColor = JSColor.FromRGB(0xB0, 0, 0); LeftLR.style.backgroundColor = JSColor.FromRGB(0x80, 0, 0); RightLR.style.backgroundColor = JSColor.FromRGB(0x80, 0, 0); #endregion page.PageContainer.AttachToDocument(); page.PageContainer.style.color = JSColor.White; page.PageContainer.style.textShadow = "#000 0px 0px 3px"; page.ElShadow.style.textShadow = "#000 0px 0px 3px"; #region AtResize Action AtResize = delegate { page.PageContainer.style.SetLocation(0, 0, Native.Window.Width, Native.Window.Height); }; AtResize(); Native.Window.onresize += delegate { AtResize(); }; #endregion var delay = new Timer( delegate { Native.Document.body.style.cursor = IStyle.CursorEnum.wait; } ); var COM46_Line_value = ""; Func<double, double> sin = Math.Sin; #region deviceorientation var gamma = 0.0; var beta = 0.0; var alpha = 0.0; Window.deviceorientation += e => { gamma = e.gamma; beta = e.beta; alpha = e.alpha; if (beta < 20) SpiderModelContent.po = 16; if (beta > 60) SpiderModelContent.po = 15; if (gamma > 30) SpiderModelContent.po = 14; if (gamma < -30) SpiderModelContent.po = 13; }; #endregion #region COM46_Line_value_loop Action COM46_Line_value_loop = null; COM46_Line_value_loop = delegate { var t = SpiderModelContent.t; page.Content2.innerText = COM46_Line_value; page.Content.innerText = "" //+ "\n: \t" + + "\nt: \t" + System.Convert.ToInt32((double)SpiderModelContent.t) + "\np: \t" + SpiderModelContent.p + "\npo: \t" + SpiderModelContent.po + "\ncamera_z: \t" + System.Convert.ToInt32((double)SpiderModelContent.camera_z) //+ "\nalpha: \t" + alpha //+ "\nbeta: \t" + beta //+ "\ngamma: \t" + gamma + "\n" + "\nRED leg1down_vertical_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg1down_vertical_deg) + "\nGREEN leg2down_vertical_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg2down_vertical_deg) + "\nBLUE leg3down_vertical_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg3down_vertical_deg) + "\nWHITE leg4down_vertical_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg4down_vertical_deg) + "\n" + "\nRED leg1up_sideway_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg1up_sideway_deg) + "\nGREEN leg2up_sideway_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg2up_sideway_deg) + "\nBLUE leg3up_sideway_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg3up_sideway_deg) + "\nWHITE leg4up_sideway_deg: \t" + System.Convert.ToInt32((double)SpiderModelContent.leg4up_sideway_deg); Native.Window.requestAnimationFrame += COM46_Line_value_loop; }; Native.Window.requestAnimationFrame += COM46_Line_value_loop; #endregion #region Connect page.Connect.onclick += delegate { SpiderModelContent.t_fix = 0; "Connect".ToDocumentTitle(); SpiderModelContent.po = 0; ; service.AtFocus(); }; #endregion #region Disconnect page.Disconnect.onclick += delegate { "Disconnect".ToDocumentTitle(); SpiderModelContent.po = 0; ; service.AtBlur(); }; #endregion Action poll = null; poll = delegate { delay.StartTimeout(400); // Send data from JavaScript to the server tier service.WebMethod2( "" + SpiderModelContent.po, COM46_Line => { Native.Document.body.style.cursor = IStyle.CursorEnum.@default; delay.Stop(); COM46_Line_value = COM46_Line.Replace("\t", "\n"); // jsc: why string.split with each not working?? var a = COM46_Line.Split(';'); byte RightLR_value = 0; byte LeftLR_value = 0; var t = 0f; #region parse RightLR, LeftLS, LeftIR, RightIR for (int i = 0; i < a.Length; i++) { var u = a[i]; u.TakeUntilOrEmpty(":").Trim().With( key => { var _value = u.SkipUntilOrEmpty(":").Trim(); // 1024 is dark #region RightLR if (key == "RS") { var value_int32 = int.Parse(_value); var value_1024 = (1024 - Math.Min(int.Parse(_value), 1024)); // jsc: please do the masking when casting to byte yyourself, thanks :) RightLR_value = (byte)((255 * value_1024 / 1024) & 0xff); RightLR_value = (byte)Math.Min(255, RightLR_value * 2); if (RightLR_value == 255) RightLR.style.backgroundColor = JSColor.Cyan; else RightLR.style.backgroundColor = JSColor.FromGray(RightLR_value); } #endregion #region LeftLS if (key == "LS") { var value_int32 = int.Parse(_value); var value_1024 = (1024 - Math.Min(int.Parse(_value), 1024)); // jsc: please do the masking when casting to byte yyourself, thanks :) LeftLR_value = (byte)((255 * value_1024 / 1024) & 0xff); LeftLR_value = (byte)Math.Min(255, LeftLR_value * 2); //LeftLR.innerText = "" + ivalue; if (LeftLR_value == 255) LeftLR.style.backgroundColor = JSColor.Cyan; else LeftLR.style.backgroundColor = JSColor.FromGray(LeftLR_value); } #endregion #region LeftIR if (key == "LI") { var value_int32 = int.Parse(_value); if (value_int32 > 400) LeftIR.style.backgroundColor = JSColor.Red; else if (value_int32 > 200) LeftIR.style.backgroundColor = JSColor.Yellow; else LeftIR.style.backgroundColor = JSColor.Green; LeftIR.style.height = value_int32 + "px"; SpiderModelContent.tween_red_obstacle_L_y((1 - value_int32 / 600) * 24); } #endregion #region RightIR if (key == "RI") { var value_int32 = int.Parse(_value); if (value_int32 > 400) RightIR.style.backgroundColor = JSColor.Red; else if (value_int32 > 200) RightIR.style.backgroundColor = JSColor.Yellow; else RightIR.style.backgroundColor = JSColor.Green; RightIR.style.height = value_int32 + "px"; SpiderModelContent.tween_red_obstacle_R_y((1 - value_int32 / 600) * 24); } #endregion if (key == "t") { t = (float)double.Parse(_value); } if (key == "pp") { SpiderModelContent.p = int.Parse(_value); } } ); } #endregion if (t != 0) if (SpiderModelContent.t_local != 0) if (SpiderModelContent.t_fix == 0) SpiderModelContent.t_fix = t - SpiderModelContent.t_local; // dark 70 .. 255 bright SpiderModelContent.tween_white_arrow_y( 50 * (1 - ((Math.Max(LeftLR_value, RightLR_value) - 70) / (255 - 70))) ); SpiderModelContent.tween_white_arrow_x( (LeftLR_value - 60) * -20f / (255 - 60) + (RightLR_value - 60) * 20f / (255 - 60) ); #region next new Timer( delegate { Native.Window.requestAnimationFrame += poll; } ).StartTimeout(UpdateSpeed); #endregion } ); page.FastUpdates.onclick += delegate { UpdateSpeed = 50; }; page.SlowUpdates.onclick += delegate { UpdateSpeed = 500; }; }; Native.Window.requestAnimationFrame += poll; }
private static void Tick(IHTMLApplet a, Action value, Timer t) { // http://www.rgagnon.com/javadetails/java-0176.html // in IE: isActive returns an error if the applet IS loaded, // false if not loaded // in NS: isActive returns true if loaded, an error if not loaded, var ie = (bool)new IFunction( "/*@cc_on return true; @*/ return false;" ).apply(null); var r = false; try { r = a.isActive(); } catch { r = ie; } if (r) { t.Stop(); if (value != null) value(); // note: this actually works! :) //Native.Window.alert("onload!"); } }
/// <summary> /// This is a javascript application. /// </summary> /// <param name="page">HTML document rendered by the web server which can now be enhanced.</param> public Application(IApp page) { var random = new Random(); device_id = random.Next(); #region con var con = new ConsoleForm(); con.InitializeConsoleFormWriter(); con.StartPosition = FormStartPosition.Manual; con.Show(); // make it slim con.Height = 100; // TopMost con.GetHTMLTarget().style.zIndex = 20002; con.Opacity = 0.9; Action Toggle = delegate { if (con.WindowState == FormWindowState.Minimized) { con.WindowState = FormWindowState.Normal; } else { con.WindowState = FormWindowState.Minimized; } // put the console far right bottom con.MoveTo( Native.window.Width - con.Width, Native.window.Height - con.Height ); }; Action<int> AtKeyCode = KeyCode => { Console.WriteLine( new { KeyCode } ); // US if (KeyCode == 222) { Toggle(); } // EE if (KeyCode == 192) { Toggle(); } }; #if onorientationchange Native.window.onorientationchange += e => { Toggle(); }; #endif Native.document.onkeyup += e => { AtKeyCode(e.KeyCode); }; Toggle(); #endregion Console.WriteLine("console ready for " + new { id = device_id }); var x = 0; var y = 0; #region Virtual Screen FormStyler.AtFormCreated = LikeDesktop; var fs = new Form { }; //fs.FormBorderStyle = FormBorderStyle.None; fs.BackColor = Color.FromArgb(0, 148, 155); fs.Width = Native.screen.width / 4; fs.Height = Native.screen.height / 4; fs.Show(); fs.Opacity = 0.5; FormStyler.AtFormCreated = LikeVirtualScreen; var fvs = new Form { Text = "Virtual Screen" }; fvs.BackColor = Color.Transparent; FormStyler.AtFormCreated = FormStyler.LikeWindowsClassic; fvs.Width = Native.screen.width / 4; fvs.Height = Native.screen.height / 4; fvs.Show(); fvs.Owner = fs; var fw = new Form { }; fw.Width = Native.window.Width / 4; fw.Height = Native.window.Height / 4; fw.Show(); fw.Owner = fvs; fw.Opacity = 0.8; KeepOwnedFormsLinkedToOwnerLocation(fs); KeepOwnedFormsLinkedToOwnerLocation(fvs); KeepOwnedFormsLinkedToOwnerLocation(fw); #endregion // doesnt work yet? //fw.SizeGripStyle = SizeGripStyle.Hide; var svg = new ISVGSVGElement().AttachTo(page.content); svg.style.SetLocation(0, 0); var vsvg = new ISVGSVGElement().AttachTo(fvs.GetHTMLTarget()); vsvg.style.SetLocation(0, 0); #region VirtualScreenUpdate Action VirtualScreenUpdate = delegate { if (fs.Capture) return; // dragging it? if (fvs.Capture) return; var max_right = fvs.OwnedForms.Max(k => k.Right); var min_left = fvs.OwnedForms.Min(k => k.Left); var max_bottom = fvs.OwnedForms.Max(k => k.Bottom); var min_top = fvs.OwnedForms.Min(k => k.Top); DisableKeepOwnedFormsLinkedToOwnerLocation = true; fvs.Left = min_left; fvs.Top = min_top; fvs.Width = max_right - min_left; fvs.Height = max_bottom - min_top; page.content.style.SetLocation( (min_left - fw.Left) * 4, (min_top - fw.Top) * 4, (max_right - min_left) * 4, (max_bottom - min_top) * 4 ); DisableKeepOwnedFormsLinkedToOwnerLocation = false; }; #endregion fw.LocationChanged += delegate { VirtualScreenUpdate(); }; #region AtResize Action AtResize = delegate { // screen can change, but only once, when window is moved to the other monitor? fs.Text = "Screen " + new { Native.screen.width, Native.screen.height }; fs.Width = Native.screen.width / 4; fs.Height = Native.screen.height / 4; fw.Text = " " + new { Native.window.Width, Native.window.Height #if onorientationchange , Native.window.orientation #endif }; fw.Width = Native.window.Width / 4; fw.Height = Native.window.Height / 4; VirtualScreenUpdate(); }; Native.window.onresize += delegate { AtResize(); }; Native.window.onfocus += delegate { AtResize(); }; Native.window.onblur += delegate { AtResize(); }; new ScriptCoreLib.JavaScript.Runtime.Timer( delegate { AtResize(); } ).StartInterval(1000 / 2); #endregion // what is attaching what? // what about await var svgcursor1ghost = new cursor1().AttachTo(page.content).ToSVG(); var svgcursor1 = new cursor1().AttachTo(page.content).ToSVG(); svgcursor1.fill += svgcursor1ghost.fill; var vcursor = new cursor1().AttachTo(fvs.GetHTMLTarget()).ToSVG(); var Shadows = new List<Form>(); Func<Form, Form> CreateShadow = _fw => { FormStyler.AtFormCreated = LikeVirtualWindow; var fwshadow = new Form(); Shadows.Add(fwshadow); fwshadow.BackColor = Color.Transparent; FormStyler.AtFormCreated = FormStyler.LikeWindowsClassic; fwshadow.Width = Native.screen.width / 4; fwshadow.Height = Native.screen.height / 4; fwshadow.Show(); Action fwshadow_update = delegate { fwshadow.MoveTo(_fw.Left, _fw.Top); fwshadow.SizeTo(_fw.Width, _fw.Height); }; _fw.LocationChanged += delegate { fwshadow_update(); }; _fw.SizeChanged += delegate { fwshadow_update(); }; fwshadow_update(); _fw.BringToFront(); return fwshadow; }; Shadows.Add(CreateShadow(fw)); bool canexit = false; bool canenter = true; Action at_exit_MultiMouseMode = delegate { //Console.WriteLine("at_exit_MultiMouseMode"); }; Action at_enter_MultiMouseMode = delegate { //Console.WriteLine("at_enter_MultiMouseMode"); }; Action<IEvent.MouseButtonEnum> at_mousedown = button => { //Console.WriteLine("at_enter_mousedown: " + button); }; Action at_mouseup = delegate { //Console.WriteLine("at_enter_mouseup"); }; var path = new ISVGPathElement().AttachTo(svg); path.setAttribute("style", "stroke: black; stroke-width: 4; fill: none;"); var path_d = ""; var vpath = new ISVGPathElement().AttachTo(vsvg); vpath.setAttribute("style", "stroke: black; stroke-width: 1; fill: none;"); var vpath_d = ""; bool internal_ismousedown = false; Action<IEvent.MouseButtonEnum> internal_mousedown = button => { internal_ismousedown = true; path = new ISVGPathElement().AttachTo(svg); if (button == IEvent.MouseButtonEnum.Left) path.setAttribute("style", "stroke: black; stroke-width: 4; fill: none;"); else path.setAttribute("style", "stroke: rgb(0, 108, 115); stroke-width: 32; fill: none;"); path_d = ""; vpath = new ISVGPathElement().AttachTo(vsvg); if (button == IEvent.MouseButtonEnum.Left) vpath.setAttribute("style", "stroke: black; stroke-width: 1; fill: none;"); else vpath.setAttribute("style", "stroke: rgb(0, 108, 115); stroke-width: 8; fill: none;"); vpath_d = ""; svgcursor1.fill(0, 0, 255); vcursor.fill(0, 0, 255); //path.d = " M100,50 L10,10 L200,200 "; path_d += " M" + x + "," + y; path.d = path_d; vpath_d += " M" + (x / 4) + "," + (y / 4); vpath.d = vpath_d; }; Action<IEvent.MouseButtonEnum> mousedown = button => { at_mousedown(button); internal_mousedown(button); }; Action internal_mouseup = delegate { internal_ismousedown = false; svgcursor1.fill(0, 255, 0); vcursor.fill(0, 255, 0); }; Action mouseup = delegate { at_mouseup(); internal_mouseup(); }; #region exit_MultiMouseMode Action internal_exit_MultiMouseMode = delegate { svgcursor1.fill(0, 0, 0); vcursor.fill(0, 0, 0); con.Opacity = 0.9; page.content.style.Opacity = 0.3; page.content.style.zIndex = 0; page.content.style.backgroundColor = "rgba(0, 148, 155, 1)"; Native.Document.body.style.backgroundColor = "black"; page.content.style.With( (dynamic s) => { s.webkitFilter = "blur(3px)"; } ); page.info.style.With( (dynamic s) => { s.webkitFilter = ""; } ); Shadows.WithEach( f => f.GetHTMLTarget().style.With( (dynamic s) => { s.webkitFilter = ""; } ) ); fs.FormsByOwnership().WithEach( f => f.GetHTMLTarget().style.With( (dynamic s) => { s.webkitFilter = ""; } ) ); fvs.OwnedForms.WithEach( k => { k.GetHTMLTarget().style.display = IStyle.DisplayEnum.block; } ); }; Action exit_MultiMouseMode = delegate { if (!canexit) return; canexit = false; canenter = true; at_exit_MultiMouseMode(); internal_exit_MultiMouseMode(); }; #endregion #region enter_MultiMouseMode Action internal_enter_MultiMouseMode = delegate { svgcursor1.fill(255, 0, 0); vcursor.fill(255, 0, 0); con.Opacity = 0.5; page.content.style.Opacity = 1.0; page.content.style.backgroundColor = ""; Native.Document.body.style.backgroundColor = "rgba(0, 148, 155, 1)"; page.content.style.zIndex = 20000; con.GetHTMLTarget().style.zIndex = 20002; page.content.style.With( (dynamic s) => { s.webkitFilter = ""; } ); page.info.style.With( (dynamic s) => { s.webkitFilter = "blur(3px)"; } ); fvs.OwnedForms.WithEach( k => { k.GetHTMLTarget().style.display = IStyle.DisplayEnum.none; } ); Shadows.WithEach( f => f.GetHTMLTarget().style.With( (dynamic s) => { s.webkitFilter = "blur(3px)"; } ) ); fs.FormsByOwnership().WithEach( f => f.GetHTMLTarget().style.With( (dynamic s) => { s.webkitFilter = "blur(3px)"; } ) ); }; Action enter_MultiMouseMode = delegate { if (!canenter) return; canexit = true; canenter = false; at_enter_MultiMouseMode(); internal_enter_MultiMouseMode(); }; #endregion #region onmousemove Native.Document.body.onmouseup += e => { if (Native.Document.pointerLockElement == Native.Document.body) { mouseup(); return; } }; Native.Document.body.onmousedown += e => { if (Native.Document.pointerLockElement == Native.Document.body) { mousedown(e.MouseButton); return; } Console.WriteLine("requesting MultiMouse mode!"); x = e.CursorX; y = e.CursorY; e.preventDefault(); Native.Document.body.requestPointerLock(); }; Action<int, int> at_set_cursor_position = delegate { }; var pxx = 0; var pyy = 0; var ghost_busy = false; Action<int, int> internal_set_cursor_position = (xx, yy) => { // already set to that exact location! if (pxx == xx) if (pyy == yy) return; pxx = xx; pyy = yy; vcursor.Element.style.SetSize( cursor1.ImageDefaultWidth / 4, cursor1.ImageDefaultHeight / 4 ); vcursor.Element.style.SetLocation( (xx - 14) / 4, (yy - (64 - 56)) / 4 ); svgcursor1.Element.style.SetLocation( xx - 14, // inscaope/svg Y is upside down! yy - (64 - 56) ); if (!ghost_busy) { ghost_busy = true; svgcursor1ghost.Element.style.Opacity = 0.2; svgcursor1ghost.Element.style.With( (dynamic s) => s.webkitTransition = "all 0.5s linear" ); svgcursor1ghost.Element.style.SetLocation( pxx - 14, // inscaope/svg Y is upside down! pyy - (64 - 56) ); new ScriptCoreLib.JavaScript.Runtime.Timer( delegate { svgcursor1ghost.Element.style.SetLocation( pxx - 14, // inscaope/svg Y is upside down! pyy - (64 - 56) ); ghost_busy = false; } ).StartTimeout(500); } // if this window will be activated next time we can continue where we were // told to.. x = xx; y = yy; if (internal_ismousedown) { path_d += " L" + x + "," + y; path.d = path_d; vpath_d += " L" + (x / 4) + "," + (y / 4); vpath.d = vpath_d; } }; Action<int, int> set_cursor_position = (xx, yy) => { at_set_cursor_position(xx, yy); internal_set_cursor_position(xx, yy); }; Native.Document.body.onmousemove += e => { if (Native.Document.pointerLockElement == Native.Document.body) { enter_MultiMouseMode(); x += e.movementX; y += e.movementY; // clip it // fullscreen behaves differently? x = x.Min(fvs.Width * 4).Max(0); y = y.Min(fvs.Height * 4).Max(0); set_cursor_position(x, y); } else { exit_MultiMouseMode(); } }; #endregion internal_exit_MultiMouseMode(); internal_set_cursor_position(0, 0); Native.document.body.ontouchstart += e => { e.preventDefault(); e.stopPropagation(); e.touches[0].With( touch => { // how do we enter? enter_MultiMouseMode(); // exit by broswer history move? set_cursor_position(touch.clientX, touch.clientY); // ipad has 11 touchpoints. multiply that with the number of devices/ // for now we support 1 pointer per session :) if (e.touches.length == 1) mousedown(IEvent.MouseButtonEnum.Left); else mousedown(IEvent.MouseButtonEnum.Right); } ); }; Native.document.body.ontouchend += e => { e.preventDefault(); e.stopPropagation(); // ipad has 11 touchpoints. multiply that with the number of devices/ // for now we support 1 pointer per session :) if (e.touches.length == 0) mouseup(); else mousedown(IEvent.MouseButtonEnum.Left); }; Native.document.body.ontouchmove += e => { e.preventDefault(); e.stopPropagation(); e.touches[0].With( touch => { set_cursor_position(touch.clientX, touch.clientY); } ); }; #region onmessage bool disable_bind_reconfigure = false; Action<int, int> internal_reconfigure = delegate { }; Action<MessageEvent, XElement> internal_onmessage = (e, xml) => { device_onmessage(0, xml); }; Native.window.onmessage += e => { // who sent this? :P var source = (string)e.data; //var now = DateTime.Now; //Console.WriteLine(now + " " + source); var xml = XElement.Parse(source); internal_onmessage(e, xml); }; var friendly_devices = new { source_device_id = 0, f = default(Form), children = new { child_id = 0, fc = default(Form) }.ToEmptyList() }.ToEmptyList(); #region device_onmessage this.device_onmessage = (source_device_id, xml) => { // mothership to local network? // source_device_id = 0 means it came from one of our virtual screens? if (xml.Name.LocalName == "at_mousedown") { int button = int.Parse(xml.Attribute("button").Value); internal_mousedown((IEvent.MouseButtonEnum)button); } if (xml.Name.LocalName == "at_mouseup") { internal_mouseup(); } if (xml.Name.LocalName == "at_enter_MultiMouseMode") { internal_enter_MultiMouseMode(); } if (xml.Name.LocalName == "at_exit_MultiMouseMode") { internal_exit_MultiMouseMode(); } if (xml.Name.LocalName == "at_set_cursor_position") { int xx = int.Parse(xml.Attribute("x").Value); int yy = int.Parse(xml.Attribute("y").Value); internal_set_cursor_position(xx, yy); } }; #endregion var ListOfChildren = new { child_id = 0, fc = default(Form) }.ToEmptyList(); // when is this called? this.device_bind = (mothership_postXElement) => { // we might now be able to invoke the server, and via that any other device Console.WriteLine("device_bind"); #region at_enter_MultiMouseMode at_enter_MultiMouseMode += delegate { var xml = new XElement("at_enter_MultiMouseMode"); mothership_postXElement(xml); }; #endregion #region at_exit_MultiMouseMode at_exit_MultiMouseMode += delegate { mothership_postXElement(new XElement("at_exit_MultiMouseMode")); }; #endregion #region at_mousedown at_mousedown += button => { mothership_postXElement(new XElement("at_mousedown", new XAttribute("button", "" + (int)button))); }; #endregion #region at_mouseup at_mouseup += delegate { mothership_postXElement(new XElement("at_mouseup")); }; #endregion #region at_set_cursor_position at_set_cursor_position += (xx, yy) => { var xml = new XElement("at_set_cursor_position", // int not yet supported? new XAttribute("x", "" + xx), new XAttribute("y", "" + yy) ); mothership_postXElement( xml ); }; #endregion // now we can reply.. this.device_onmessage += (source_device_id, xml) => { #region at_virtualwindowsync_reconfigure if (source_device_id != 0) if (xml.Name.LocalName == "at_virtualwindowsync_reconfigure") { int __device_id = int.Parse(xml.Attribute("device_id").Value); if (__device_id == device_id) { // are we being reconfigured? friendly_devices.Where(k => k.source_device_id == source_device_id).WithEach( q => { int dx = int.Parse(xml.Attribute("dx").Value); int dy = int.Parse(xml.Attribute("dy").Value); disable_bind_reconfigure = true; q.f.MoveTo( fw.Left - dx, fw.Top - dy ); disable_bind_reconfigure = false; } ); } } #endregion #region at_virtualwindowsync if (source_device_id != 0) if (xml.Name.LocalName == "at_virtualwindowsync") { Console.WriteLine("got at_virtualwindowsync"); // do we know this device? var q = friendly_devices.FirstOrDefault(k => k.source_device_id == source_device_id); int w = int.Parse(xml.Attribute("w").Value); int h = int.Parse(xml.Attribute("h").Value); Action reposition = delegate { }; if (q == null) { var fc = new Form { Text = new { source_device_id }.ToString() }; q = new { source_device_id, f = fc, children = new { child_id = 0, fc = default(Form) }.ToEmptyList() }; friendly_devices.Add(q); q.f.StartPosition = FormStartPosition.Manual; q.f.Show(); // show should respect opacity? q.f.Opacity = 0.3; // where to put it? // left or right? var max_right = fvs.OwnedForms.Max(k => k.Right); var min_left = fvs.OwnedForms.Min(k => k.Left); if (source_device_id < device_id) q.f.Left = min_left - w; else q.f.Left = max_right; q.f.Top = fw.Top; q.f.Owner = fvs; var fcShadow = CreateShadow(q.f); Shadows.Add(fcShadow); #region from now on if we move any of our screens // in relation to this source_device_id we have to notify it Action SendDelta = delegate { var pdx = fc.Left - fw.Left; var pdy = fc.Top - fw.Top; mothership_postXElement( new XElement("at_virtualwindowsync_reconfigure", new XAttribute("device_id", "" + source_device_id), new XAttribute("dx", "" + pdx), new XAttribute("dy", "" + pdy) ) ); }; fw.LocationChanged += delegate { if (disable_bind_reconfigure) return; SendDelta(); }; fc.LocationChanged += delegate { if (disable_bind_reconfigure) return; SendDelta(); }; #endregion } // thanks for letting us know that you changed your size... q.f.Width = w; q.f.Height = h; xml.Elements("child").WithEach( cxml => { // any new children? int child_id = int.Parse(cxml.Attribute("child_id").Value); int pdx = int.Parse(cxml.Attribute("pdx").Value); int pdy = int.Parse(cxml.Attribute("pdy").Value); int cw = int.Parse(cxml.Attribute("w").Value); int ch = int.Parse(cxml.Attribute("h").Value); var cq = q.children.FirstOrDefault(k => k.child_id == child_id); if (cq == null) { var fc = new Form { Text = new { source_device_id, child_id }.ToString() }; cq = new { child_id, fc }; q.children.Add(cq); cq.fc.StartPosition = FormStartPosition.Manual; cq.fc.Show(); // show should respect opacity? cq.fc.Opacity = 0.2; // if this child needs to be between then add it // before reposition cq.fc.Owner = fvs; var fcShadow = CreateShadow(cq.fc); Shadows.Add(fcShadow); } cq.fc.Left = q.f.Left + pdx; cq.fc.Top = q.f.Top + pdy; // thanks for letting us know that you changed your size... cq.fc.Width = cw; cq.fc.Height = ch; } ); } #endregion }; // lets tell the world about virtual screens owned by us. // lets start by advertising our size. #region at_virtualwindowsync var t = new ScriptCoreLib.JavaScript.Runtime.Timer( delegate { // do we know whats the dx to other windows? var xml = new XElement("at_virtualwindowsync", // int not yet supported? new XAttribute("w", "" + fw.Width), new XAttribute("h", "" + fw.Height) ); #region what about children? ListOfChildren.WithEach( c => { var pdx = c.fc.Left - fw.Left; var pdy = c.fc.Top - fw.Top; xml.Add( new XElement("child", new XAttribute("child_id", "" + c.child_id), // int not yet supported? new XAttribute("pdx", "" + pdx), new XAttribute("pdy", "" + pdy), new XAttribute("w", "" + c.fc.Width), new XAttribute("h", "" + c.fc.Height) ) ); } ); #endregion mothership_postXElement( xml ); Console.WriteLine("sent at_virtualwindowsync"); } ); t.StartInterval(5000); #endregion }; Action<IWindow, Form> bind = (w, fc) => { this.device_bind(w.postXElement); internal_onmessage += (e, xml) => { if (xml.Name.LocalName == "reconfigure") { // how do we know this reconfigrue event is for us? if (e.source == w) { disable_bind_reconfigure = true; int dx = int.Parse(xml.Attribute("dx").Value); int dy = int.Parse(xml.Attribute("dy").Value); //Console.WriteLine("reconfigure " + new { dx, dy, fw.Left }); //fw.Left += dx; //fw.Top += dy; fc.MoveTo( fw.Left - dx, fw.Top - dy ); disable_bind_reconfigure = false; } } }; Action SendDelta = delegate { var pdx = fc.Left - fw.Left; var pdy = fc.Top - fw.Top; w.postXElement( new XElement("reconfigure", new XAttribute("dx", "" + pdx), new XAttribute("dy", "" + pdy) ) ); }; fw.LocationChanged += delegate { if (disable_bind_reconfigure) return; SendDelta(); }; fc.LocationChanged += delegate { if (disable_bind_reconfigure) return; SendDelta(); }; }; #endregion #region opener Native.window.opener.With( w => { // disable features page.info.Hide(); Console.WriteLine("we have opener: " + w.document.location.href); var fc = new Form { Text = "opener" }; fc.Owner = fvs; Action cAtResize = delegate { fc.Text = "Opener " + new { w.Width, w.Height }; fc.Width = w.Width / 4; fc.Height = w.Height / 4; }; w.onresize += delegate { cAtResize(); }; var ct = new ScriptCoreLib.JavaScript.Runtime.Timer( delegate { cAtResize(); } ); ct.StartInterval(1000 / 15); cAtResize(); fc.StartPosition = FormStartPosition.Manual; fc.Show(); fc.Opacity = 0.7; fc.BackColor = Color.Transparent; var fcShadow = CreateShadow(fc); Shadows.Add(fcShadow); Native.window.requestAnimationFrame += delegate { // ScriptCoreLib Windows Forms has a few bugs:P fc.MoveTo(fw.Left - fc.Width, fw.Top); bind(w, fc); }; } ); #endregion #region make info clickable page.info.onmousedown += e => { if (internal_ismousedown) return; e.stopPropagation(); }; page.info.ontouchstart += e => { if (internal_ismousedown) return; e.stopPropagation(); }; page.info.ontouchmove += e => { if (internal_ismousedown) return; e.stopPropagation(); }; page.info.ontouchend += e => { if (internal_ismousedown) return; e.stopPropagation(); }; #endregion #region OpenChildSession page.OpenChildSession.onclick += e => { e.preventDefault(); Console.WriteLine("open child session..."); Native.window.open( Native.Document.location.href, "_blank", 400, 400, true).With( w => { w.onload += delegate { if (w.document.location.href == "about:blank") return; Console.WriteLine("child onload " + w.document.location.href); var fc = new Form { Text = "child" }; Action cAtResize = delegate { fc.Text = "Child " + new { w.Width, w.Height }; fc.Width = w.Width / 4; fc.Height = w.Height / 4; VirtualScreenUpdate(); }; w.onresize += delegate { cAtResize(); }; var ct = new ScriptCoreLib.JavaScript.Runtime.Timer( delegate { cAtResize(); } ); ct.StartInterval(1000 / 2); //cAtResize(); fc.StartPosition = FormStartPosition.Manual; fc.Show(); fc.Opacity = 0.5; // first child could be a monitor to our right fc.MoveTo(fw.Right, fw.Top); fc.Owner = fvs; fc.BackColor = Color.Transparent; fc.Width = 400 / 4; fc.Height = 400 / 4; VirtualScreenUpdate(); fc.LocationChanged += delegate { VirtualScreenUpdate(); }; var fcShadow = CreateShadow(fc); Shadows.Add(fcShadow); var token = new { child_id = random.Next(), fc }; ListOfChildren.Add(token); #region FormClosing w.onbeforeunload += delegate { if (fc == null) return; w = null; ct.Stop(); fc.Close(); fc = null; }; Native.window.onbeforeunload += delegate { if (w == null) return; w.close(); w = null; }; fc.FormClosing += delegate { if (w == null) return; ListOfChildren.Remove(token); Shadows.Remove(fcShadow); fc = null; w.close(); w = null; }; #endregion bind(w, fc); }; } ); }; #endregion Native.document.documentElement.style.overflow = IStyle.OverflowEnum.hidden; }
public MineSweeperPanel(int ButtonsX = 15, int ButtonsY = 16, double Mines = 0.2, Assets MyAssets = null) { if (MyAssets == null) MyAssets = Assets.Default; Control.style.position = IStyle.PositionEnum.relative; Control.style.backgroundColor = Color.FromGray(192); MineField = new MineSweeperControl(ButtonsX, ButtonsY, Mines, MyAssets); ControlWidth = MineField.Width + 20; ControlHeight = MineField.Height + 50; Control.style.SetSize(ControlWidth, ControlHeight); MineField.Control.AttachTo(Control).style.SetLocation(10, 40); var face = new Button(FaceSize, FaceSize); face.Source = MyAssets.face_ok; face.MouseDownSource = MyAssets.face_ok_down; var timer = new RedNumberDisplay(3, 0, MyAssets); var actualtimer = new Timer( t => { timer.Value = t.Counter; } ); MineField.Bang += () => { face.Source = MyAssets.face_dead; actualtimer.Stop(); }; MineField.LookingForMines += () => face.Source = MyAssets.face_scared; MineField.DoneLookingForMines += () => face.Source = MyAssets.face_ok; face.Click += () => { face.Source = MyAssets.face_ok; actualtimer.Stop(); timer.Value = 0; MineField.Reset(); }; MineField.AllMinesFound += delegate { face.Source = MyAssets.face_cool; actualtimer.Stop(); MineField.Alive = false; MineField.DisableButtons(); }; face.Control.AttachTo(Control); face.Control.style.SetLocation(10 + (MineField.Width - FaceSize) / 2, 6); var minecounter = new RedNumberDisplay(3, MineField.MinesTotal, MyAssets); minecounter.Control.AttachTo(Control); minecounter.Control.style.SetLocation(10, 6); timer.Control.AttachTo(Control); timer.Control.style.SetLocation(10 + MineField.Width - timer.Width, 6); MineField.MinesFoundChanged += () => minecounter.Value = MineField.MinesTotal - MineField.MinesFound; MineField.Control.style.border = "1px inset gray"; minecounter.Control.style.border = "1px inset gray"; timer.Control.style.border = "1px inset gray"; this.Control.style.border = "1px outset gray"; MineField.DoneLookingForMines += () => { if (!actualtimer.IsAlive) actualtimer.StartInterval(1000); }; }