Update fork from latests changes
This commit is contained in:
commit
5cbd9e42b5
|
@ -3,6 +3,7 @@
|
|||
|
||||
# Autosave files
|
||||
*~
|
||||
.vs/
|
||||
|
||||
# build
|
||||
[Oo]bj/
|
||||
|
|
|
@ -8,10 +8,12 @@ namespace Ooui.AspNetCore
|
|||
public class ElementResult : ActionResult
|
||||
{
|
||||
readonly Element element;
|
||||
readonly string title;
|
||||
|
||||
public ElementResult (Element element)
|
||||
public ElementResult (Element element, string title = "")
|
||||
{
|
||||
this.element = element;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public override async Task ExecuteResultAsync (ActionContext context)
|
||||
|
@ -20,10 +22,11 @@ namespace Ooui.AspNetCore
|
|||
response.StatusCode = 200;
|
||||
response.ContentType = "text/html; charset=utf-8";
|
||||
var sessionId = WebSocketHandler.BeginSession (context.HttpContext, element);
|
||||
var html = Encoding.UTF8.GetBytes (UI.RenderTemplate (WebSocketHandler.WebSocketPath + "?id=" + sessionId));
|
||||
response.ContentLength = html.Length;
|
||||
var html = UI.RenderTemplate (WebSocketHandler.WebSocketPath + "?id=" + sessionId, title: title);
|
||||
var htmlBytes = Encoding.UTF8.GetBytes (html);
|
||||
response.ContentLength = htmlBytes.Length;
|
||||
using (var s = response.Body) {
|
||||
await s.WriteAsync (html, 0, html.Length).ConfigureAwait (false);
|
||||
await s.WriteAsync (htmlBytes, 0, htmlBytes.Length).ConfigureAwait (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,19 +32,30 @@ namespace Ooui.AspNetCore
|
|||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static async Task HandleWebSocketRequestAsync (HttpContext context)
|
||||
{
|
||||
void BadRequest (string message)
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
context.Response.ContentType = "text/plain; charset=utf-8";
|
||||
using (var sw = new System.IO.StreamWriter (context.Response.Body)) {
|
||||
sw.WriteLine (message);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure we get a good ID
|
||||
//
|
||||
if (!context.Request.Query.TryGetValue ("id", out var idValues)) {
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
BadRequest ("Missing `id`");
|
||||
return;
|
||||
}
|
||||
|
||||
var id = idValues.FirstOrDefault ();
|
||||
var id = idValues.LastOrDefault ();
|
||||
if (id == null || id.Length != 32) {
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
BadRequest ("Invalid `id`");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,7 +63,7 @@ namespace Ooui.AspNetCore
|
|||
// Find the pending session
|
||||
//
|
||||
if (!pendingSessions.TryRemove (id, out var pendingSession)) {
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
BadRequest ("Unknown `id`");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,16 +71,32 @@ namespace Ooui.AspNetCore
|
|||
// Reject the session if it's old
|
||||
//
|
||||
if ((DateTime.UtcNow - pendingSession.RequestTimeUtc) > SessionTimeout) {
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
BadRequest ("Old `id`");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the element's dimensions
|
||||
//
|
||||
if (!context.Request.Query.TryGetValue ("w", out var wValues) || wValues.Count < 1) {
|
||||
BadRequest ("Missing `w`");
|
||||
return;
|
||||
}
|
||||
if (!context.Request.Query.TryGetValue ("h", out var hValues) || hValues.Count < 1) {
|
||||
BadRequest ("Missing `h`");
|
||||
return;
|
||||
}
|
||||
if (!double.TryParse (wValues.Last (), out var w))
|
||||
w = 640;
|
||||
if (!double.TryParse (hValues.Last (), out var h))
|
||||
h = 480;
|
||||
|
||||
//
|
||||
// OK, Run
|
||||
//
|
||||
var token = CancellationToken.None;
|
||||
var webSocket = await context.WebSockets.AcceptWebSocketAsync ("ooui");
|
||||
var session = new Ooui.UI.Session (webSocket, pendingSession.Element, token);
|
||||
var session = new Ooui.UI.Session (webSocket, pendingSession.Element, w, h, token);
|
||||
await session.RunAsync ().ConfigureAwait (false);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
using System.Web;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
namespace Ooui.Forms
|
||||
{
|
||||
public class DisplayAlert
|
||||
{
|
||||
private readonly Button _closeButton;
|
||||
private readonly Button _acceptButton;
|
||||
private readonly Button _cancelButton;
|
||||
|
||||
public DisplayAlert(AlertArguments arguments)
|
||||
{
|
||||
Element = new Div
|
||||
{
|
||||
ClassName = "modal-dialog"
|
||||
};
|
||||
|
||||
var content = new Div
|
||||
{
|
||||
ClassName = "modal-content"
|
||||
};
|
||||
|
||||
var header = new Div
|
||||
{
|
||||
ClassName = "modal-header"
|
||||
};
|
||||
|
||||
_closeButton = new Button
|
||||
{
|
||||
ClassName = "close"
|
||||
};
|
||||
|
||||
_closeButton.AppendChild(new Span(HttpUtility.HtmlDecode("×")));
|
||||
|
||||
var h4 = new Heading(4)
|
||||
{
|
||||
Text = arguments.Title
|
||||
};
|
||||
|
||||
header.AppendChild(_closeButton);
|
||||
header.AppendChild(h4);
|
||||
|
||||
content.AppendChild(header);
|
||||
content.AppendChild(new Div()
|
||||
{
|
||||
ClassName = "modal-body",
|
||||
Text = arguments.Message
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(arguments.Cancel))
|
||||
{
|
||||
var footer = new Div()
|
||||
{
|
||||
ClassName = "modal-footer"
|
||||
};
|
||||
|
||||
_cancelButton = new Button(arguments.Cancel)
|
||||
{
|
||||
ClassName = "btn btn-default"
|
||||
};
|
||||
_cancelButton.Clicked += (s, e) => SetResult(false);
|
||||
|
||||
footer.AppendChild(_cancelButton);
|
||||
|
||||
if (!string.IsNullOrEmpty(arguments.Accept))
|
||||
{
|
||||
_acceptButton = new Button(arguments.Accept)
|
||||
{
|
||||
ClassName = "btn btn-default"
|
||||
};
|
||||
|
||||
_acceptButton.Clicked += (s, e) => SetResult(true);
|
||||
footer.AppendChild(_acceptButton);
|
||||
}
|
||||
|
||||
content.AppendChild(footer);
|
||||
}
|
||||
|
||||
|
||||
Element.AppendChild(content);
|
||||
|
||||
void SetResult(bool result)
|
||||
{
|
||||
arguments.SetResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
public event TargetEventHandler Clicked
|
||||
{
|
||||
add
|
||||
{
|
||||
_closeButton.Clicked += value;
|
||||
|
||||
if(_cancelButton != null)
|
||||
_cancelButton.Clicked += value;
|
||||
|
||||
if(_acceptButton != null)
|
||||
_acceptButton.Clicked += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_closeButton.Clicked -= value;
|
||||
|
||||
if (_cancelButton != null)
|
||||
_cancelButton.Clicked -= value;
|
||||
|
||||
if (_acceptButton != null)
|
||||
_acceptButton.Clicked -= value;
|
||||
}
|
||||
}
|
||||
public Element Element { get; private set; }
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using Xamarin.Forms;
|
|||
using Xamarin.Forms.Internals;
|
||||
|
||||
[assembly: Dependency (typeof (ResourcesProvider))]
|
||||
[assembly: ExportRenderer (typeof (BoxView), typeof (BoxRenderer))]
|
||||
[assembly: ExportRenderer (typeof (Button), typeof (ButtonRenderer))]
|
||||
[assembly: ExportRenderer (typeof (Label), typeof (LabelRenderer))]
|
||||
|
||||
|
|
|
@ -8,15 +8,35 @@ namespace Ooui.Forms.Extensions
|
|||
public static SizeRequest GetSizeRequest (this Ooui.Element self, double widthConstraint, double heightConstraint,
|
||||
double minimumWidth = -1, double minimumHeight = -1)
|
||||
{
|
||||
var s = self.Text.MeasureSize (self.Style);
|
||||
var rw = 0.0;
|
||||
var rh = 0.0;
|
||||
Size s = new Size (0, 0);
|
||||
var measured = false;
|
||||
|
||||
var request = new Size (
|
||||
double.IsPositiveInfinity (s.Width) ? double.PositiveInfinity : s.Width,
|
||||
double.IsPositiveInfinity (s.Height) ? double.PositiveInfinity : s.Height);
|
||||
var minimum = new Size (minimumWidth < 0 ? request.Width : minimumWidth,
|
||||
minimumHeight < 0 ? request.Height : minimumHeight);
|
||||
if (self.Style.Width.Equals ("inherit")) {
|
||||
s = self.Text.MeasureSize (self.Style);
|
||||
measured = true;
|
||||
rw = double.IsPositiveInfinity (s.Width) ? double.PositiveInfinity : s.Width;
|
||||
}
|
||||
else {
|
||||
rw = self.Style.GetNumberWithUnits ("width", "px", 640);
|
||||
}
|
||||
|
||||
return new SizeRequest (request, minimum);
|
||||
if (self.Style.Height.Equals ("inherit")) {
|
||||
if (!measured) {
|
||||
s = self.Text.MeasureSize (self.Style);
|
||||
measured = true;
|
||||
}
|
||||
rh = double.IsPositiveInfinity (s.Height) ? double.PositiveInfinity : s.Height;
|
||||
}
|
||||
else {
|
||||
rh = self.Style.GetNumberWithUnits ("height", "px", 480);
|
||||
}
|
||||
|
||||
var minimum = new Size (minimumWidth < 0 ? rw : minimumWidth,
|
||||
minimumHeight < 0 ? rh : minimumHeight);
|
||||
|
||||
return new SizeRequest (new Size (rw, rh), minimum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,55 @@ namespace Ooui.Forms.Extensions
|
|||
{
|
||||
public static class FontExtensions
|
||||
{
|
||||
public static void SetStyleFont (this View view, Style style)
|
||||
public static void SetStyleFont (this View view, string family, double size, FontAttributes attrs, Style style)
|
||||
{
|
||||
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
|
||||
if (size == 14.0) {
|
||||
style.FontSize = null;
|
||||
}
|
||||
else {
|
||||
style.FontSize = size;
|
||||
}
|
||||
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
|
||||
|
||||
if (string.IsNullOrEmpty (family)) {
|
||||
style.FontFamily = null;
|
||||
}
|
||||
else {
|
||||
style.FontFamily = family;
|
||||
}
|
||||
|
||||
if (attrs.HasFlag (FontAttributes.Bold)) {
|
||||
style.FontWeight = "bold";
|
||||
}
|
||||
else {
|
||||
style.FontWeight = null;
|
||||
}
|
||||
|
||||
if (attrs.HasFlag (FontAttributes.Italic)) {
|
||||
style.FontStyle = "italic";
|
||||
}
|
||||
else {
|
||||
style.FontStyle = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Size MeasureSize (this string text, string fontFamily, double fontSize, FontAttributes fontAttrs)
|
||||
{
|
||||
if (string.IsNullOrEmpty (text))
|
||||
return Size.Zero;
|
||||
|
||||
var fontHeight = fontSize;
|
||||
var charWidth = fontSize * 0.5;
|
||||
|
||||
var width = text.Length * charWidth;
|
||||
|
||||
return new Size (width, fontHeight);
|
||||
}
|
||||
|
||||
public static Size MeasureSize (this string text, Style style)
|
||||
{
|
||||
return MeasureSize (text, "", 14, FontAttributes.None);
|
||||
}
|
||||
|
||||
public static string ToOouiTextAlign (this TextAlignment align)
|
||||
|
@ -22,17 +69,5 @@ namespace Ooui.Forms.Extensions
|
|||
}
|
||||
}
|
||||
|
||||
public static Size MeasureSize (this string text, Style style)
|
||||
{
|
||||
if (string.IsNullOrEmpty (text))
|
||||
return Size.Zero;
|
||||
|
||||
var fontHeight = 16.0;
|
||||
var charWidth = 8.0;
|
||||
|
||||
var width = text.Length * charWidth;
|
||||
|
||||
return new Size (width, fontHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Xamarin.Forms
|
|||
Device.SetIdiom (TargetIdiom.Desktop);
|
||||
Device.PlatformServices = new OouiPlatformServices ();
|
||||
Device.Info = new OouiDeviceInfo ();
|
||||
Color.SetAccent (Color.FromHex ("#0000EE")); // Safari Blue
|
||||
|
||||
Registrar.RegisterAll (new[] {
|
||||
typeof(ExportRendererAttribute),
|
||||
|
@ -110,7 +111,13 @@ namespace Xamarin.Forms
|
|||
|
||||
public void StartTimer (TimeSpan interval, Func<bool> callback)
|
||||
{
|
||||
throw new NotImplementedException ();
|
||||
Timer timer = null;
|
||||
timer = new Timer ((_ => {
|
||||
if (!callback ()) {
|
||||
timer?.Dispose ();
|
||||
timer = null;
|
||||
}
|
||||
}), null, (int)interval.TotalMilliseconds, (int)interval.TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<PackageReference Include="Xamarin.Forms" Version="2.4.0.38779" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Renderers\" />
|
||||
<Folder Include="Extensions\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -16,16 +16,24 @@ namespace Xamarin.Forms
|
|||
Ooui.UI.Publish (path, () => lazyPage.Value);
|
||||
}
|
||||
|
||||
public static Ooui.Element CreateElement (this Xamarin.Forms.Page page)
|
||||
public static Ooui.Element GetOouiElement (this Xamarin.Forms.Page page)
|
||||
{
|
||||
if (!Xamarin.Forms.Forms.IsInitialized)
|
||||
throw new InvalidOperationException ("call Forms.Init() before this");
|
||||
|
||||
var existingRenderer = Ooui.Forms.Platform.GetRenderer (page);
|
||||
if (existingRenderer != null)
|
||||
return existingRenderer.NativeView;
|
||||
|
||||
return CreateElement (page);
|
||||
}
|
||||
|
||||
static Ooui.Element CreateElement (this Xamarin.Forms.Page page)
|
||||
{
|
||||
if (!(page.RealParent is Application)) {
|
||||
var app = new DefaultApplication ();
|
||||
app.MainPage = page;
|
||||
}
|
||||
|
||||
var result = new Ooui.Forms.Platform ();
|
||||
result.SetPage (page);
|
||||
return result.Element;
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||
using Ooui.Forms.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Internals;
|
||||
using System.Web;
|
||||
|
||||
namespace Ooui.Forms
|
||||
{
|
||||
|
@ -31,6 +32,20 @@ namespace Ooui.Forms
|
|||
public Platform ()
|
||||
{
|
||||
_renderer = new PlatformRenderer (this);
|
||||
|
||||
_renderer.Style.PropertyChanged += HandleRendererStyle_PropertyChanged;
|
||||
|
||||
MessagingCenter.Subscribe (this, Page.AlertSignalName, (Page sender, AlertArguments arguments) => {
|
||||
var alert = new DisplayAlert (arguments);
|
||||
alert.Clicked += CloseAlert;
|
||||
|
||||
_renderer.AppendChild (alert.Element);
|
||||
|
||||
void CloseAlert (object s, EventArgs e)
|
||||
{
|
||||
_renderer.RemoveChild (alert.Element);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void IDisposable.Dispose ()
|
||||
|
@ -114,6 +129,12 @@ namespace Ooui.Forms
|
|||
Console.Error.WriteLine ("Potential view double add");
|
||||
}
|
||||
|
||||
void HandleRendererStyle_PropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
var pageRenderer = GetRenderer (Page);
|
||||
pageRenderer?.SetElementSize (Ooui.Forms.Extensions.ElementExtensions.GetSizeRequest (_renderer, double.PositiveInfinity, double.PositiveInfinity).Request);
|
||||
}
|
||||
|
||||
void INavigation.InsertPageBefore (Page page, Page before)
|
||||
{
|
||||
throw new NotImplementedException ();
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace Ooui.Forms
|
|||
|
||||
public Platform Platform => platform;
|
||||
|
||||
public override bool WantsFullScreen => true;
|
||||
|
||||
public PlatformRenderer (Platform platform)
|
||||
{
|
||||
this.platform = platform;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using Ooui.Forms.Extensions;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Ooui.Forms.Renderers
|
||||
{
|
||||
public class BoxRenderer : VisualElementRenderer<BoxView>
|
||||
{
|
||||
Ooui.Color _colorToRenderer;
|
||||
|
||||
protected override void OnElementChanged (ElementChangedEventArgs<BoxView> e)
|
||||
{
|
||||
base.OnElementChanged (e);
|
||||
|
||||
if (Element != null)
|
||||
SetBackgroundColor (Element.BackgroundColor);
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged (sender, e);
|
||||
if (e.PropertyName == BoxView.ColorProperty.PropertyName)
|
||||
SetBackgroundColor (Element.BackgroundColor);
|
||||
}
|
||||
|
||||
protected override void SetBackgroundColor (Xamarin.Forms.Color color)
|
||||
{
|
||||
if (Element == null)
|
||||
return;
|
||||
|
||||
var elementColor = Element.Color;
|
||||
if (!elementColor.IsDefault)
|
||||
_colorToRenderer = elementColor.ToOouiColor ();
|
||||
else
|
||||
_colorToRenderer = Colors.Clear;
|
||||
|
||||
Style.BackgroundColor = _colorToRenderer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,13 @@ namespace Ooui.Forms.Renderers
|
|||
Ooui.Color _buttonTextColorDefaultHighlighted;
|
||||
Ooui.Color _buttonTextColorDefaultNormal;
|
||||
|
||||
public override SizeRequest GetDesiredSize (double widthConstraint, double heightConstraint)
|
||||
{
|
||||
var size = Element.Text.MeasureSize (Element.FontFamily, Element.FontSize, Element.FontAttributes);
|
||||
size = new Size (size.Width, size.Height * 1.428 + 14);
|
||||
return new SizeRequest (size, size);
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (Control != null) {
|
||||
|
@ -31,6 +38,8 @@ namespace Ooui.Forms.Renderers
|
|||
|
||||
Debug.Assert (Control != null, "Control != null");
|
||||
|
||||
Control.ClassName = "btn btn-primary";
|
||||
|
||||
_buttonTextColorDefaultNormal = Ooui.Colors.Black;
|
||||
_buttonTextColorDefaultHighlighted = Ooui.Colors.Black;
|
||||
_buttonTextColorDefaultDisabled = Ooui.Colors.Black;
|
||||
|
@ -98,7 +107,7 @@ namespace Ooui.Forms.Renderers
|
|||
|
||||
void UpdateFont ()
|
||||
{
|
||||
Element.SetStyleFont (Control.Style);
|
||||
Element.SetStyleFont (Element.FontFamily, Element.FontSize, Element.FontAttributes, Control.Style);
|
||||
}
|
||||
|
||||
void UpdateImage ()
|
||||
|
@ -141,14 +150,10 @@ namespace Ooui.Forms.Renderers
|
|||
void UpdateTextColor ()
|
||||
{
|
||||
if (Element.TextColor == Xamarin.Forms.Color.Default) {
|
||||
Control.Style.Color = _buttonTextColorDefaultNormal;
|
||||
Control.Style.Color = _buttonTextColorDefaultHighlighted;
|
||||
Control.Style.Color = _buttonTextColorDefaultDisabled;
|
||||
Control.Style.Color = null;
|
||||
}
|
||||
else {
|
||||
Control.Style.Color = Element.TextColor.ToOouiColor ();
|
||||
Control.Style.Color = Element.TextColor.ToOouiColor ();
|
||||
Control.Style.Color = _buttonTextColorDefaultDisabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Ooui.Forms.Extensions;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Ooui.Forms.Renderers
|
||||
{
|
||||
public class EntryRenderer : ViewRenderer<Entry, Ooui.Input>
|
||||
{
|
||||
Ooui.Color _defaultTextColor;
|
||||
bool _disposed;
|
||||
|
||||
static Size initialSize = Size.Zero;
|
||||
|
||||
public EntryRenderer ()
|
||||
{
|
||||
}
|
||||
|
||||
public override SizeRequest GetDesiredSize (double widthConstraint, double heightConstraint)
|
||||
{
|
||||
return base.GetDesiredSize (widthConstraint, heightConstraint);
|
||||
}
|
||||
|
||||
IElementController ElementController => Element as IElementController;
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_disposed = true;
|
||||
|
||||
if (disposing) {
|
||||
if (Control != null) {
|
||||
//Control.Inputted -= OnEditingBegan;
|
||||
Control.Inputted -= OnEditingChanged;
|
||||
Control.Changed -= OnEditingEnded;
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose (disposing);
|
||||
}
|
||||
|
||||
protected override void OnElementChanged (ElementChangedEventArgs<Entry> e)
|
||||
{
|
||||
base.OnElementChanged (e);
|
||||
|
||||
if (e.NewElement == null)
|
||||
return;
|
||||
|
||||
if (Control == null) {
|
||||
var textField = new Ooui.Input (InputType.Text);
|
||||
SetNativeControl (textField);
|
||||
|
||||
_defaultTextColor = Colors.Black;
|
||||
|
||||
textField.Inputted += OnEditingChanged;
|
||||
|
||||
//textField.EditingDidBegin += OnEditingBegan;
|
||||
textField.Changed += OnEditingEnded;
|
||||
}
|
||||
|
||||
UpdatePlaceholder ();
|
||||
UpdatePassword ();
|
||||
UpdateText ();
|
||||
UpdateColor ();
|
||||
UpdateFont ();
|
||||
UpdateKeyboard ();
|
||||
UpdateAlignment ();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == Entry.PlaceholderProperty.PropertyName || e.PropertyName == Entry.PlaceholderColorProperty.PropertyName)
|
||||
UpdatePlaceholder ();
|
||||
else if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
|
||||
UpdatePassword ();
|
||||
else if (e.PropertyName == Entry.TextProperty.PropertyName)
|
||||
UpdateText ();
|
||||
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
|
||||
UpdateColor ();
|
||||
else if (e.PropertyName == Xamarin.Forms.InputView.KeyboardProperty.PropertyName)
|
||||
UpdateKeyboard ();
|
||||
else if (e.PropertyName == Entry.HorizontalTextAlignmentProperty.PropertyName)
|
||||
UpdateAlignment ();
|
||||
else if (e.PropertyName == Entry.FontAttributesProperty.PropertyName)
|
||||
UpdateFont ();
|
||||
else if (e.PropertyName == Entry.FontFamilyProperty.PropertyName)
|
||||
UpdateFont ();
|
||||
else if (e.PropertyName == Entry.FontSizeProperty.PropertyName)
|
||||
UpdateFont ();
|
||||
else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName) {
|
||||
UpdateColor ();
|
||||
UpdatePlaceholder ();
|
||||
}
|
||||
|
||||
base.OnElementPropertyChanged (sender, e);
|
||||
}
|
||||
|
||||
void OnEditingBegan (object sender, EventArgs e)
|
||||
{
|
||||
ElementController.SetValueFromRenderer (VisualElement.IsFocusedPropertyKey, true);
|
||||
}
|
||||
|
||||
void OnEditingChanged (object sender, EventArgs eventArgs)
|
||||
{
|
||||
ElementController.SetValueFromRenderer (Entry.TextProperty, Control.Value);
|
||||
}
|
||||
|
||||
void OnEditingEnded (object sender, EventArgs e)
|
||||
{
|
||||
// Typing aid changes don't always raise EditingChanged event
|
||||
if (Control.Text != Element.Text) {
|
||||
ElementController.SetValueFromRenderer (Entry.TextProperty, Control.Text);
|
||||
}
|
||||
|
||||
ElementController.SetValueFromRenderer (VisualElement.IsFocusedPropertyKey, false);
|
||||
}
|
||||
|
||||
void UpdateAlignment ()
|
||||
{
|
||||
Control.Style.TextAlign = Element.HorizontalTextAlignment.ToOouiTextAlign ();
|
||||
}
|
||||
|
||||
void UpdateColor ()
|
||||
{
|
||||
var textColor = Element.TextColor;
|
||||
|
||||
if (textColor.IsDefault || !Element.IsEnabled)
|
||||
Control.Style.Color = _defaultTextColor;
|
||||
else
|
||||
Control.Style.Color = textColor.ToOouiColor ();
|
||||
}
|
||||
|
||||
void UpdateFont ()
|
||||
{
|
||||
if (initialSize == Size.Zero) {
|
||||
var testString = "Tj";
|
||||
initialSize = testString.MeasureSize (Control.Style);
|
||||
}
|
||||
|
||||
Element.SetStyleFont (Element.FontFamily, Element.FontSize, Element.FontAttributes, Control.Style);
|
||||
}
|
||||
|
||||
void UpdateKeyboard ()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdatePassword ()
|
||||
{
|
||||
Control.Type = Element.IsPassword ? InputType.Password : InputType.Text;
|
||||
}
|
||||
|
||||
void UpdatePlaceholder ()
|
||||
{
|
||||
Control.Placeholder = Element.Placeholder;
|
||||
}
|
||||
|
||||
void UpdateText ()
|
||||
{
|
||||
// ReSharper disable once RedundantCheckBeforeAssignment
|
||||
if (Control.Text != Element.Text)
|
||||
Control.Text = Element.Text;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,8 +17,8 @@ namespace Ooui.Forms.Renderers
|
|||
public override SizeRequest GetDesiredSize (double widthConstraint, double heightConstraint)
|
||||
{
|
||||
if (!_perfectSizeValid) {
|
||||
_perfectSize = base.GetDesiredSize (double.PositiveInfinity, double.PositiveInfinity);
|
||||
_perfectSize.Minimum = new Size (Math.Min (10, _perfectSize.Request.Width), _perfectSize.Request.Height);
|
||||
var size = Element.Text.MeasureSize (Element.FontFamily, Element.FontSize, Element.FontAttributes);
|
||||
_perfectSize = new SizeRequest (size, size);
|
||||
_perfectSizeValid = true;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ namespace Ooui.Forms.Renderers
|
|||
return;
|
||||
_perfectSizeValid = false;
|
||||
|
||||
Element.SetStyleFont (Control.Style);
|
||||
Element.SetStyleFont (Element.FontFamily, Element.FontSize, Element.FontAttributes, Control.Style);
|
||||
}
|
||||
|
||||
void UpdateTextColor ()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using Xamarin.Forms;
|
||||
|
@ -141,10 +142,10 @@ namespace Ooui.Forms
|
|||
bool shouldUpdate = width > 0 && height > 0 && parent != null && (boundsChanged || parentBoundsChanged);
|
||||
if (shouldUpdate) {
|
||||
uiview.Style.Position = "absolute";
|
||||
uiview.Style.Left = x + "px";
|
||||
uiview.Style.Top = y + "px";
|
||||
uiview.Style.Width = width + "px";
|
||||
uiview.Style.Height = height + "px";
|
||||
uiview.Style.Left = x;
|
||||
uiview.Style.Top = y;
|
||||
uiview.Style.Width = width;
|
||||
uiview.Style.Height = height;
|
||||
Renderer.SetControlSize (new Size (width, height));
|
||||
}
|
||||
else if (width <= 0 || height <= 0) {
|
||||
|
@ -157,33 +158,33 @@ namespace Ooui.Forms
|
|||
uiview.Style.Opacity = opacity;
|
||||
}
|
||||
|
||||
//var transform = 0;
|
||||
//const double epsilon = 0.001;
|
||||
//caLayer.AnchorPoint = new PointF (anchorX - 0.5f, anchorY - 0.5f);
|
||||
var transforms = "";
|
||||
var transformOrigin = default (string);
|
||||
const double epsilon = 0.001;
|
||||
|
||||
//// position is relative to anchor point
|
||||
//if (Math.Abs (anchorX - .5) > epsilon)
|
||||
// transform = transform.Translate ((anchorX - .5f) * width, 0, 0);
|
||||
//if (Math.Abs (anchorY - .5) > epsilon)
|
||||
// transform = transform.Translate (0, (anchorY - .5f) * height, 0);
|
||||
var icult = System.Globalization.CultureInfo.InvariantCulture;
|
||||
|
||||
//if (Math.Abs (translationX) > epsilon || Math.Abs (translationY) > epsilon)
|
||||
// transform = transform.Translate (translationX, translationY, 0);
|
||||
// position is relative to anchor point
|
||||
if ((Math.Abs (anchorX - 0.5) > epsilon) || (Math.Abs (anchorY - 0.5) > epsilon)) {
|
||||
transformOrigin = string.Format (icult, "{0:0.######}% {1:0.######}%", anchorX*100, anchorY*100);
|
||||
}
|
||||
|
||||
//if (Math.Abs (scale - 1) > epsilon)
|
||||
// transform = transform.Scale (scale);
|
||||
if (Math.Abs (translationX) > epsilon || Math.Abs (translationY) > epsilon)
|
||||
transforms = string.Format (icult, "{0} translate({1:0.######}px,{2:0.######}px)", transforms, translationX, translationY);
|
||||
|
||||
//// not just an optimization, iOS will not "pixel align" a view which has m34 set
|
||||
//if (Math.Abs (rotationY % 180) > epsilon || Math.Abs (rotationX % 180) > epsilon)
|
||||
// transform.m34 = 1.0f / -400f;
|
||||
if (Math.Abs (scale - 1) > epsilon)
|
||||
transforms = string.Format (icult, "{0} scale({1:0.######},{1:0.######})", transforms, scale);
|
||||
|
||||
//if (Math.Abs (rotationX % 360) > epsilon)
|
||||
// transform = transform.Rotate (rotationX * (float)Math.PI / 180.0f, 1.0f, 0.0f, 0.0f);
|
||||
// RotateX (rotationX);
|
||||
//if (Math.Abs (rotationY % 360) > epsilon)
|
||||
// transform = transform.Rotate (rotationY * (float)Math.PI / 180.0f, 0.0f, 1.0f, 0.0f);
|
||||
//RotateY (rotationY);
|
||||
|
||||
//transform = transform.Rotate (rotation * (float)Math.PI / 180.0f, 0.0f, 0.0f, 1.0f);
|
||||
//caLayer.Transform = transform;
|
||||
if (Math.Abs (rotation % 360) > epsilon)
|
||||
transforms = string.Format (icult, "{0} rotate({1:0.######}deg)", transforms, rotation);
|
||||
|
||||
uiview.Style.Transform = transforms.Length > 0 ? transforms : null;
|
||||
uiview.Style.TransformOrigin = transforms.Length > 0 ? transformOrigin : null;
|
||||
|
||||
_lastBounds = view.Bounds;
|
||||
_lastParentBounds = viewParent?.Bounds ?? Rectangle.Zero;
|
||||
|
|
|
@ -18,10 +18,32 @@ const mouseEvents = {
|
|||
wheel: true,
|
||||
};
|
||||
|
||||
// Try to close the socket gracefully
|
||||
window.onbeforeunload = function() {
|
||||
if (socket != null) {
|
||||
socket.close (1001, "Unloading page");
|
||||
socket = null;
|
||||
console.log ("Web socket closed");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSize () {
|
||||
return {
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth
|
||||
};
|
||||
}
|
||||
|
||||
// Main entrypoint
|
||||
function ooui (rootElementPath) {
|
||||
var opened = false;
|
||||
|
||||
socket = new WebSocket ("ws://" + document.location.host + rootElementPath, "ooui");
|
||||
var initialSize = getSize ();
|
||||
var wsArgs = (rootElementPath.indexOf("?") >= 0 ? "&" : "?") +
|
||||
"w=" + initialSize.width + "&h=" + initialSize.height;
|
||||
|
||||
socket = new WebSocket ("ws://" + document.location.host + rootElementPath + wsArgs, "ooui");
|
||||
|
||||
socket.addEventListener ("open", function (event) {
|
||||
console.log ("Web socket opened");
|
||||
|
@ -52,6 +74,34 @@ function ooui (rootElementPath) {
|
|||
});
|
||||
|
||||
console.log("Web socket created");
|
||||
|
||||
// Throttled window resize event
|
||||
(function() {
|
||||
window.addEventListener("resize", resizeThrottler, false);
|
||||
|
||||
var resizeTimeout;
|
||||
function resizeThrottler() {
|
||||
if (!resizeTimeout) {
|
||||
resizeTimeout = setTimeout(function() {
|
||||
resizeTimeout = null;
|
||||
actualResizeHandler();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
function resizeHandler() {
|
||||
const em = {
|
||||
m: "event",
|
||||
id: 42,
|
||||
k: "window.resize",
|
||||
v: getSize (),
|
||||
};
|
||||
const ems = JSON.stringify (em);
|
||||
if (socket != null)
|
||||
socket.send (ems);
|
||||
if (debug) console.log ("Event", em);
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
function getNode (id) {
|
||||
|
@ -135,6 +185,7 @@ function msgListen (m) {
|
|||
};
|
||||
}
|
||||
const ems = JSON.stringify (em);
|
||||
if (socket != null)
|
||||
socket.send (ems);
|
||||
if (debug) console.log ("Event", em);
|
||||
if (em.k === "submit")
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using StyleValue = System.Object;
|
||||
|
||||
namespace Ooui
|
||||
{
|
||||
public struct Color
|
||||
[Newtonsoft.Json.JsonConverter (typeof (ColorJsonConverter))]
|
||||
public struct Color : IEquatable<Color>
|
||||
{
|
||||
public byte R, G, B, A;
|
||||
|
||||
|
@ -33,9 +34,70 @@ namespace Ooui
|
|||
set => A = value >= 1.0 ? (byte)255 : ((value <= 0.0) ? (byte)0 : (byte)(value * 255.0 + 0.5));
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
if (obj is Color other)
|
||||
return R == other.R && G == other.G && B == other.B && A == other.A;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals (Color other) => R == other.R && G == other.G && B == other.B && A == other.A;
|
||||
|
||||
public override int GetHashCode () => R.GetHashCode () + G.GetHashCode () * 2 + B.GetHashCode () * 3 + A.GetHashCode () * 5;
|
||||
|
||||
public static Color FromStyleValue (StyleValue styleColor)
|
||||
{
|
||||
if (styleColor is Color c)
|
||||
return c;
|
||||
if (styleColor is string s)
|
||||
return Parse (s);
|
||||
return Colors.Clear;
|
||||
}
|
||||
|
||||
public static Color Parse (string styleValue)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace (styleValue) || styleValue.Length < 4)
|
||||
throw new ArgumentException ("Cannot parse empty strings", nameof (styleValue));
|
||||
|
||||
if (styleValue.Length > 32)
|
||||
throw new ArgumentException ("Color string is too long", nameof (styleValue));
|
||||
|
||||
if (styleValue == "inherit")
|
||||
return Colors.Clear;
|
||||
|
||||
//if (styleValue[0] == '#' && styleValue.Length == 4) {
|
||||
//}
|
||||
|
||||
//if (styleValue[0] == '#' && styleValue.Length == 7) {
|
||||
//}
|
||||
|
||||
throw new ArgumentException ($"Cannot parse color string `{styleValue}`", nameof (styleValue));
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
if (A == 255)
|
||||
return string.Format ("#{0:x2}{1:x2}{2:x2}", R, G, B);
|
||||
return string.Format ("rgba({0},{1},{2},{3})", R, G, B, A / 255.0);
|
||||
}
|
||||
}
|
||||
|
||||
class ColorJsonConverter : Newtonsoft.Json.JsonConverter
|
||||
{
|
||||
public override bool CanConvert (Type objectType)
|
||||
{
|
||||
return objectType == typeof (Color);
|
||||
}
|
||||
|
||||
public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var str = reader.ReadAsString ();
|
||||
return Color.Parse (str);
|
||||
}
|
||||
|
||||
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue (value.ToString ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,12 @@ namespace Ooui
|
|||
remove => RemoveEventListener ("wheel", value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A signal to Ooui that this element should take up the
|
||||
/// entire browser window.
|
||||
/// </summary>
|
||||
public virtual bool WantsFullScreen => false;
|
||||
|
||||
protected Element (string tagName)
|
||||
: base (tagName)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,12 @@ namespace Ooui
|
|||
remove => RemoveEventListener ("input", value);
|
||||
}
|
||||
|
||||
string placeholder = "";
|
||||
public string Placeholder {
|
||||
get => placeholder;
|
||||
set => SetProperty (ref placeholder, value, "placeholder");
|
||||
}
|
||||
|
||||
bool isChecked = false;
|
||||
public bool IsChecked {
|
||||
get => isChecked;
|
||||
|
|
149
Ooui/Platform.cs
149
Ooui/Platform.cs
|
@ -18,67 +18,60 @@ namespace Ooui
|
|||
static readonly Type androidActivityType;
|
||||
static readonly Type androidWebViewType;
|
||||
|
||||
static Platform()
|
||||
static Platform ()
|
||||
{
|
||||
var asms = AppDomain.CurrentDomain.GetAssemblies().ToDictionary(
|
||||
x => x.GetName().Name);
|
||||
var asms = AppDomain.CurrentDomain.GetAssemblies ().ToDictionary (
|
||||
x => x.GetName ().Name);
|
||||
|
||||
asms.TryGetValue("Xamarin.iOS", out iosAssembly);
|
||||
if (iosAssembly != null)
|
||||
{
|
||||
iosUIViewControllerType = iosAssembly.GetType("UIKit.UIViewController");
|
||||
iosUIApplicationType = iosAssembly.GetType("UIKit.UIApplication");
|
||||
iosUIWebViewType = iosAssembly.GetType("UIKit.UIWebView");
|
||||
iosNSUrl = iosAssembly.GetType("Foundation.NSUrl");
|
||||
iosNSUrlRequest = iosAssembly.GetType("Foundation.NSUrlRequest");
|
||||
asms.TryGetValue ("Xamarin.iOS", out iosAssembly);
|
||||
if (iosAssembly != null) {
|
||||
iosUIViewControllerType = iosAssembly.GetType ("UIKit.UIViewController");
|
||||
iosUIApplicationType = iosAssembly.GetType ("UIKit.UIApplication");
|
||||
iosUIWebViewType = iosAssembly.GetType ("UIKit.UIWebView");
|
||||
iosNSUrl = iosAssembly.GetType ("Foundation.NSUrl");
|
||||
iosNSUrlRequest = iosAssembly.GetType ("Foundation.NSUrlRequest");
|
||||
}
|
||||
|
||||
asms.TryGetValue("Mono.Android", out androidAssembly);
|
||||
if (androidAssembly != null)
|
||||
{
|
||||
androidActivityType = androidAssembly.GetType("Android.App.Activity");
|
||||
androidWebViewType = androidAssembly.GetType("Android.Webkit.WebView");
|
||||
asms.TryGetValue ("Mono.Android", out androidAssembly);
|
||||
if (androidAssembly != null) {
|
||||
androidActivityType = androidAssembly.GetType ("Android.App.Activity");
|
||||
androidWebViewType = androidAssembly.GetType ("Android.Webkit.WebView");
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenBrowser(string url, object presenter)
|
||||
public static void OpenBrowser (string url, object presenter)
|
||||
{
|
||||
if (iosAssembly != null)
|
||||
{
|
||||
OpenBrowserOniOS(url, presenter);
|
||||
if (iosAssembly != null) {
|
||||
OpenBrowserOniOS (url, presenter);
|
||||
}
|
||||
else if (androidAssembly != null)
|
||||
{
|
||||
OpenBrowserOnAndroid(url, presenter);
|
||||
else if (androidAssembly != null) {
|
||||
OpenBrowserOnAndroid (url, presenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartBrowserProcess(url);
|
||||
else {
|
||||
StartBrowserProcess (url);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpenBrowserOnAndroid(string url, object presenter)
|
||||
static void OpenBrowserOnAndroid (string url, object presenter)
|
||||
{
|
||||
var presenterType = GetObjectType(presenter);
|
||||
var presenterType = GetObjectType (presenter);
|
||||
|
||||
object presenterWebView = null;
|
||||
if (presenter != null && androidWebViewType.IsAssignableFrom(presenterType))
|
||||
{
|
||||
if (presenter != null && androidWebViewType.IsAssignableFrom (presenterType)) {
|
||||
presenterWebView = presenter;
|
||||
}
|
||||
|
||||
if (presenterWebView == null)
|
||||
{
|
||||
throw new ArgumentException("Presenter must be a WebView", nameof(presenter));
|
||||
if (presenterWebView == null) {
|
||||
throw new ArgumentException ("Presenter must be a WebView", nameof(presenter));
|
||||
}
|
||||
|
||||
var m = androidWebViewType.GetMethod("LoadUrl", BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, new Type[] { typeof(string) }, null);
|
||||
m.Invoke(presenterWebView, new object[] { url });
|
||||
var m = androidWebViewType.GetMethod ("LoadUrl", BindingFlags.Public|BindingFlags.Instance, null, CallingConventions.Any, new Type[] { typeof(string) }, null);
|
||||
m.Invoke (presenterWebView, new object[] { url });
|
||||
}
|
||||
|
||||
static void OpenBrowserOniOS(string url, object presenter)
|
||||
static void OpenBrowserOniOS (string url, object presenter)
|
||||
{
|
||||
var presenterType = GetObjectType(presenter);
|
||||
var presenterType = GetObjectType (presenter);
|
||||
|
||||
//
|
||||
// Find a presenter view controller
|
||||
|
@ -87,85 +80,58 @@ namespace Ooui
|
|||
// 3. Create a window?
|
||||
//
|
||||
object presenterViewController = null;
|
||||
if (presenter != null && iosUIViewControllerType.IsAssignableFrom(presenterType))
|
||||
{
|
||||
if (presenter != null && iosUIViewControllerType.IsAssignableFrom (presenterType)) {
|
||||
presenterViewController = presenter;
|
||||
}
|
||||
|
||||
if (presenterViewController == null)
|
||||
{
|
||||
var app = iosUIApplicationType.GetProperty("SharedApplication").GetValue(null, null);
|
||||
var window = iosUIApplicationType.GetProperty("KeyWindow").GetValue(app, null);
|
||||
if (window != null)
|
||||
{
|
||||
var rvc = window.GetType().GetProperty("RootViewController").GetValue(window, null);
|
||||
if (rvc != null)
|
||||
{
|
||||
var pvc = rvc.GetType().GetProperty("PresentedViewController").GetValue(rvc, null);
|
||||
if (presenterViewController == null) {
|
||||
var app = iosUIApplicationType.GetProperty ("SharedApplication").GetValue (null, null);
|
||||
var window = iosUIApplicationType.GetProperty ("KeyWindow").GetValue (app, null);
|
||||
if (window != null) {
|
||||
var rvc = window.GetType ().GetProperty ("RootViewController").GetValue (window, null);
|
||||
if (rvc != null) {
|
||||
var pvc = rvc.GetType ().GetProperty ("PresentedViewController").GetValue (rvc, null);
|
||||
presenterViewController = pvc ?? rvc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (presenterViewController == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot find a view controller from which to present");
|
||||
if (presenterViewController == null) {
|
||||
throw new InvalidOperationException ("Cannot find a view controller from which to present");
|
||||
}
|
||||
|
||||
//
|
||||
// Create the browser
|
||||
//
|
||||
var browserVC = Activator.CreateInstance(iosUIViewControllerType);
|
||||
var browserV = Activator.CreateInstance(iosUIWebViewType);
|
||||
var browserVC = Activator.CreateInstance (iosUIViewControllerType);
|
||||
var browserV = Activator.CreateInstance (iosUIWebViewType);
|
||||
|
||||
var nsUrl = iosNSUrl.GetMethod("FromString").Invoke(null, new object[] { url });
|
||||
var nsUrlRequest = iosNSUrlRequest.GetMethod("FromUrl").Invoke(null, new object[] { nsUrl });
|
||||
iosUIWebViewType.GetMethod("LoadRequest").Invoke(browserV, new object[] { nsUrlRequest });
|
||||
iosUIViewControllerType.GetProperty("View").SetValue(browserVC, browserV, null);
|
||||
var nsUrl = iosNSUrl.GetMethod ("FromString").Invoke (null, new object[] { url });
|
||||
var nsUrlRequest = iosNSUrlRequest.GetMethod ("FromUrl").Invoke (null, new object[] { nsUrl });
|
||||
iosUIWebViewType.GetMethod ("LoadRequest").Invoke (browserV, new object[] { nsUrlRequest });
|
||||
iosUIViewControllerType.GetProperty ("View").SetValue (browserVC, browserV, null);
|
||||
|
||||
var m = iosUIViewControllerType.GetMethod("PresentViewController");
|
||||
var m = iosUIViewControllerType.GetMethod ("PresentViewController");
|
||||
|
||||
// Console.WriteLine (presenterViewController);
|
||||
// Console.WriteLine (browserVC);
|
||||
m.Invoke(presenterViewController, new object[] { browserVC, false, null });
|
||||
m.Invoke (presenterViewController, new object[] { browserVC, false, null });
|
||||
}
|
||||
|
||||
static Type GetObjectType(object o)
|
||||
static Type GetObjectType (object o)
|
||||
{
|
||||
var t = typeof(object);
|
||||
if (o is IReflectableType rt)
|
||||
{
|
||||
t = rt.GetTypeInfo().AsType();
|
||||
var t = typeof (object);
|
||||
if (o is IReflectableType rt) {
|
||||
t = rt.GetTypeInfo ().AsType ();
|
||||
}
|
||||
else if (o != null)
|
||||
{
|
||||
t = o.GetType();
|
||||
else if (o != null) {
|
||||
t = o.GetType ();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static Process StartBrowserProcess(string url)
|
||||
static Process StartBrowserProcess (string url)
|
||||
{
|
||||
var cmd = url;
|
||||
var args = string.Empty;
|
||||
|
||||
var osv = Environment.OSVersion;
|
||||
|
||||
if (osv.Platform == PlatformID.Unix)
|
||||
{
|
||||
cmd = "open";
|
||||
args = url;
|
||||
}
|
||||
|
||||
var platform = (int)Environment.OSVersion.Platform;
|
||||
var isWindows = ((platform != 4) && (platform != 6) && (platform != 128));
|
||||
|
||||
if (isWindows)
|
||||
{
|
||||
cmd = "explorer.exe";
|
||||
args = url;
|
||||
}
|
||||
|
||||
// var vs = Environment.GetEnvironmentVariables ();
|
||||
// foreach (System.Collections.DictionaryEntry kv in vs) {
|
||||
// System.Console.WriteLine($"K={kv.Key}, V={kv.Value}");
|
||||
|
@ -173,8 +139,9 @@ namespace Ooui
|
|||
|
||||
// Console.WriteLine ($"Process.Start {cmd} {args}");
|
||||
|
||||
return Process.Start(cmd, args);
|
||||
|
||||
return Environment.OSVersion.Platform == PlatformID.Unix
|
||||
? Process.Start ("open", url)
|
||||
: Process.Start (new ProcessStartInfo (url) { UseShellExecute = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@ namespace Ooui
|
|||
|
||||
readonly Dictionary<string, Value> properties =
|
||||
new Dictionary<string, Value> ();
|
||||
static readonly private char[] numberChars = new char[] {
|
||||
'0','1','2','3','4','5','6','7','8','9',
|
||||
'.','-','+',
|
||||
};
|
||||
|
||||
public Value AlignSelf {
|
||||
get => this["align-self"];
|
||||
|
@ -126,7 +130,7 @@ namespace Ooui
|
|||
|
||||
public Value Bottom {
|
||||
get => this["bottom"];
|
||||
set => this["bottom"] = value;
|
||||
set => this["bottom"] = AddNumberUnits (value, "px");
|
||||
}
|
||||
|
||||
public Value Clear {
|
||||
|
@ -176,7 +180,7 @@ namespace Ooui
|
|||
|
||||
public Value FontSize {
|
||||
get => this["font-size"];
|
||||
set => this["font-size"] = value;
|
||||
set => this["font-size"] = AddNumberUnits (value, "px");
|
||||
}
|
||||
|
||||
public Value FontStyle {
|
||||
|
@ -196,12 +200,12 @@ namespace Ooui
|
|||
|
||||
public Value Height {
|
||||
get => this["height"];
|
||||
set => this["height"] = value;
|
||||
set => this["height"] = AddNumberUnits (value, "px");
|
||||
}
|
||||
|
||||
public Value Left {
|
||||
get => this["left"];
|
||||
set => this["left"] = value;
|
||||
set => this["left"] = AddNumberUnits (value, "px");
|
||||
}
|
||||
|
||||
public Value LineHeight {
|
||||
|
@ -301,7 +305,17 @@ namespace Ooui
|
|||
|
||||
public Value Top {
|
||||
get => this["top"];
|
||||
set => this["top"] = value;
|
||||
set => this["top"] = AddNumberUnits (value, "px");
|
||||
}
|
||||
|
||||
public Value Transform {
|
||||
get => this["transform"];
|
||||
set => this["transform"] = value;
|
||||
}
|
||||
|
||||
public Value TransformOrigin {
|
||||
get => this["transform-origin"];
|
||||
set => this["transform-origin"] = value;
|
||||
}
|
||||
|
||||
public Value VerticalAlign {
|
||||
|
@ -316,7 +330,7 @@ namespace Ooui
|
|||
|
||||
public Value Width {
|
||||
get => this["width"];
|
||||
set => this["width"] = value;
|
||||
set => this["width"] = AddNumberUnits (value, "px");
|
||||
}
|
||||
|
||||
public Value ZIndex {
|
||||
|
@ -386,5 +400,34 @@ namespace Ooui
|
|||
}
|
||||
return o.ToString ();
|
||||
}
|
||||
|
||||
static string AddNumberUnits (object val, string units)
|
||||
{
|
||||
if (val is string s)
|
||||
return s;
|
||||
if (val is IConvertible c)
|
||||
return c.ToString (System.Globalization.CultureInfo.InvariantCulture) + units;
|
||||
return val.ToString ();
|
||||
}
|
||||
|
||||
public double GetNumberWithUnits (string key, string units, double baseValue)
|
||||
{
|
||||
var v = this[key];
|
||||
if (v == null)
|
||||
return 0;
|
||||
|
||||
if (v is string s) {
|
||||
var lastIndex = s.LastIndexOfAny (numberChars);
|
||||
if (lastIndex < 0)
|
||||
return 0;
|
||||
var num = double.Parse (s.Substring (0, lastIndex + 1), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
|
||||
return num;
|
||||
}
|
||||
|
||||
if (v is IConvertible c)
|
||||
return c.ToDouble (System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
59
Ooui/UI.cs
59
Ooui/UI.cs
|
@ -34,10 +34,11 @@ namespace Ooui
|
|||
<head>
|
||||
<title>@Title</title>
|
||||
<meta name=""viewport"" content=""width=device-width, initial-scale=1"" />
|
||||
<link rel=""stylesheet"" href=""https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"" />
|
||||
<style>@Styles</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id=""ooui-body""></div>
|
||||
<div id=""ooui-body"" class=""container-fluid""></div>
|
||||
<script src=""/ooui.js""></script>
|
||||
<script>ooui(""@WebSocketPath"");</script>
|
||||
</body>
|
||||
|
@ -299,9 +300,9 @@ namespace Ooui
|
|||
}
|
||||
}
|
||||
|
||||
public static string RenderTemplate (string webSocketPath)
|
||||
public static string RenderTemplate (string webSocketPath, string title = "")
|
||||
{
|
||||
return Template.Replace ("@WebSocketPath", webSocketPath).Replace ("@Styles", rules.ToString ());
|
||||
return Template.Replace ("@WebSocketPath", webSocketPath).Replace ("@Styles", rules.ToString ()).Replace ("@Title", title);
|
||||
}
|
||||
|
||||
class DataHandler : RequestHandler
|
||||
|
@ -435,7 +436,7 @@ namespace Ooui
|
|||
// Create a new session and let it handle everything from here
|
||||
//
|
||||
try {
|
||||
var session = new Session (webSocket, element, serverToken);
|
||||
var session = new Session (webSocket, element, 1024, 768, serverToken);
|
||||
await session.RunAsync ().ConfigureAwait (false);
|
||||
}
|
||||
catch (WebSocketException ex) when (ex.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely) {
|
||||
|
@ -472,11 +473,15 @@ namespace Ooui
|
|||
readonly System.Timers.Timer sendThrottle;
|
||||
DateTime lastTransmitTime = DateTime.MinValue;
|
||||
readonly TimeSpan throttleInterval = TimeSpan.FromSeconds (1.0 / 30); // 30 FPS max
|
||||
readonly double initialWidth;
|
||||
readonly double initialHeight;
|
||||
|
||||
public Session (WebSocket webSocket, Element element, CancellationToken serverToken)
|
||||
public Session (WebSocket webSocket, Element element, double initialWidth, double initialHeight, CancellationToken serverToken)
|
||||
{
|
||||
this.webSocket = webSocket;
|
||||
this.element = element;
|
||||
this.initialWidth = initialWidth;
|
||||
this.initialHeight = initialHeight;
|
||||
|
||||
//
|
||||
// Create a new session cancellation token that will trigger
|
||||
|
@ -524,6 +529,10 @@ namespace Ooui
|
|||
//
|
||||
// Add it to the document body
|
||||
//
|
||||
if (element.WantsFullScreen) {
|
||||
element.Style.Width = initialWidth;
|
||||
element.Style.Height = initialHeight;
|
||||
}
|
||||
QueueMessage (Message.Call ("document.body", "appendChild", element));
|
||||
|
||||
//
|
||||
|
@ -570,34 +579,39 @@ namespace Ooui
|
|||
}
|
||||
}
|
||||
|
||||
void QueueStateMessages (EventTarget target)
|
||||
void QueueStateMessagesLocked (EventTarget target)
|
||||
{
|
||||
if (target == null) return;
|
||||
var created = false;
|
||||
foreach (var m in target.StateMessages) {
|
||||
QueueMessage (m);
|
||||
if (m.MessageType == MessageType.Create) {
|
||||
createdIds.Add (m.TargetId);
|
||||
created = true;
|
||||
}
|
||||
if (created) {
|
||||
QueueMessageLocked (m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QueueMessage (Message message)
|
||||
void QueueMessageLocked (Message message)
|
||||
{
|
||||
//
|
||||
// Make sure all the referenced objects have been created
|
||||
//
|
||||
if (message.MessageType == MessageType.Create) {
|
||||
createdIds.Add (message.TargetId);
|
||||
}
|
||||
else {
|
||||
if (!createdIds.Contains (message.TargetId)) {
|
||||
createdIds.Add (message.TargetId);
|
||||
QueueStateMessages (element.GetElementById (message.TargetId));
|
||||
QueueStateMessagesLocked (element.GetElementById (message.TargetId));
|
||||
}
|
||||
if (message.Value is Array a) {
|
||||
if (message.Value is EventTarget ve) {
|
||||
if (!createdIds.Contains (ve.Id)) {
|
||||
QueueStateMessagesLocked (ve);
|
||||
}
|
||||
}
|
||||
else if (message.Value is Array a) {
|
||||
for (var i = 0; i < a.Length; i++) {
|
||||
// Console.WriteLine ($"A{i} = {a.GetValue(i)}");
|
||||
if (a.GetValue (i) is EventTarget e && !createdIds.Contains (e.Id)) {
|
||||
createdIds.Add (e.Id);
|
||||
QueueStateMessages (e);
|
||||
}
|
||||
QueueStateMessagesLocked (e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -605,7 +619,14 @@ namespace Ooui
|
|||
//
|
||||
// Add it to the queue
|
||||
//
|
||||
lock (queuedMessages) queuedMessages.Add (message);
|
||||
queuedMessages.Add (message);
|
||||
}
|
||||
|
||||
void QueueMessage (Message message)
|
||||
{
|
||||
lock (queuedMessages) {
|
||||
QueueMessageLocked (message);
|
||||
}
|
||||
sendThrottle.Enabled = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="2.4.0.38779" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -19,5 +20,6 @@
|
|||
<ProjectReference Include="..\..\Ooui.AspNetCore\Ooui.AspNetCore.csproj" />
|
||||
<ProjectReference Include="..\..\Ooui\Ooui.csproj" />
|
||||
<ProjectReference Include="..\..\Samples\Samples.csproj" />
|
||||
<ProjectReference Include="..\..\Ooui.Forms\Ooui.Forms.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -18,33 +18,16 @@ namespace AspNetCoreMvc.Controllers
|
|||
return View ();
|
||||
}
|
||||
|
||||
public IActionResult Clicker ()
|
||||
{
|
||||
var count = 0;
|
||||
var head = new Heading { Text = "Click away!" };
|
||||
var label = new Label { Text = "0" };
|
||||
var btn = new Button { Text = "Increase" };
|
||||
btn.Clicked += (sender, e) => {
|
||||
count++;
|
||||
label.Text = count.ToString ();
|
||||
};
|
||||
var div = new Div ();
|
||||
div.AppendChild (head);
|
||||
div.AppendChild (label);
|
||||
div.AppendChild (btn);
|
||||
return new ElementResult (div);
|
||||
}
|
||||
|
||||
public IActionResult About ()
|
||||
{
|
||||
ViewData["Message"] = "Your application description page.";
|
||||
ViewData["Message"] = "Ooui is a mini web framework to make programming interactive UIs easy.";
|
||||
|
||||
return View ();
|
||||
}
|
||||
|
||||
public IActionResult Contact ()
|
||||
{
|
||||
ViewData["Message"] = "Your contact page.";
|
||||
ViewData["Message"] = "Find us on github.";
|
||||
|
||||
return View ();
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using AspNetCoreMvc.Models;
|
||||
using Ooui;
|
||||
using Ooui.AspNetCore;
|
||||
using Samples;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace AspNetCoreMvc.Controllers
|
||||
{
|
||||
|
@ -35,14 +37,21 @@ namespace AspNetCoreMvc.Controllers
|
|||
var sampleType = typeof (Samples.ISample);
|
||||
var asm = sampleType.Assembly;
|
||||
var sampleTypes = asm.GetTypes ().Where (x => x.Name.EndsWith ("Sample", StringComparison.Ordinal) && x != sampleType);
|
||||
var samples = from t in sampleTypes let s = Activator.CreateInstance (t) as Samples.ISample where s != null select s;
|
||||
var samples = from t in sampleTypes
|
||||
let s = Activator.CreateInstance (t) as Samples.ISample
|
||||
where s != null
|
||||
orderby s.Title
|
||||
select s;
|
||||
return samples.ToList ();
|
||||
}), true);
|
||||
|
||||
static readonly ConcurrentDictionary<string, Element> sharedSamples =
|
||||
new ConcurrentDictionary<string, Element> ();
|
||||
|
||||
public static List<Samples.ISample> Samples => lazySamples.Value;
|
||||
|
||||
[Route("/Samples/Run/{name}")]
|
||||
public IActionResult Run (string name)
|
||||
[Route ("/Samples/Run/{name}")]
|
||||
public IActionResult Run (string name, bool shared)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace (name) || name.Length > 32)
|
||||
return BadRequest ();
|
||||
|
@ -51,7 +60,24 @@ namespace AspNetCoreMvc.Controllers
|
|||
if (s == null)
|
||||
return NotFound ();
|
||||
|
||||
return new ElementResult (s.CreateElement ());
|
||||
var element = shared ? GetSharedSample (s) : s.CreateElement ();
|
||||
|
||||
return new ElementResult (element, title: s.Title + " - Ooui Samples");
|
||||
}
|
||||
|
||||
private Element GetSharedSample (ISample s)
|
||||
{
|
||||
if (sharedSamples.TryGetValue (s.Title, out var e))
|
||||
return e;
|
||||
e = s.CreateElement ();
|
||||
sharedSamples[s.Title] = e;
|
||||
return e;
|
||||
}
|
||||
|
||||
[Route ("/shared-button")]
|
||||
public IActionResult SharedButton ()
|
||||
{
|
||||
return Run ("Button Counter", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,14 +12,15 @@ namespace AspNetCoreMvc
|
|||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
public static void Main (string[] args)
|
||||
{
|
||||
BuildWebHost(args).Run();
|
||||
BuildWebHost (args).Run ();
|
||||
}
|
||||
|
||||
public static IWebHost BuildWebHost(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
public static IWebHost BuildWebHost (string[] args) =>
|
||||
WebHost.CreateDefaultBuilder (args)
|
||||
.UseConfiguration (new ConfigurationBuilder ().AddCommandLine (args).Build ())
|
||||
.UseStartup<Startup> ()
|
||||
.Build ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace AspNetCoreMvc
|
|||
|
||||
app.UseOoui ();
|
||||
|
||||
Xamarin.Forms.Forms.Init ();
|
||||
|
||||
app.UseMvc (routes => {
|
||||
routes.MapRoute (
|
||||
name: "default",
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
<h2>@ViewData["Title"].</h2>
|
||||
<h3>@ViewData["Message"]</h3>
|
||||
|
||||
<p>Use this area to provide additional information.</p>
|
||||
<p>Find out more <a href="https://github.com/praeclarum/Ooui">on github</a></p>
|
||||
|
|
|
@ -4,14 +4,3 @@
|
|||
<h2>@ViewData["Title"].</h2>
|
||||
<h3>@ViewData["Message"]</h3>
|
||||
|
||||
<address>
|
||||
One Microsoft Way<br />
|
||||
Redmond, WA 98052-6399<br />
|
||||
<abbr title="Phone">P:</abbr>
|
||||
425.555.0100
|
||||
</address>
|
||||
|
||||
<address>
|
||||
<strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br />
|
||||
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
|
||||
</address>
|
||||
|
|
|
@ -8,16 +8,19 @@
|
|||
</div>
|
||||
<div class="col-md-2">
|
||||
<h1>Ooui</h1>
|
||||
<p>Write interactive web apps in C#</p>
|
||||
<p>Write interactive web apps in C# and F#</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" style="margin-top:4em;">
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<h3>Samples</h3>
|
||||
<ul>
|
||||
@foreach (var s in SamplesController.Samples) {
|
||||
<li><a asp-area="" asp-controller="Samples" asp-action="Run" asp-route-name="@s.Title">@s.Title</a></li>
|
||||
<li>
|
||||
<a asp-area="" asp-controller="Samples" asp-action="Run" asp-route-name="@s.Title">@s.Title</a>
|
||||
(<a asp-area="" asp-controller="Samples" asp-action="Run" asp-route-name="@s.Title" asp-route-shared="@true">Shared</a>)
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
<ul class="nav navbar-nav">
|
||||
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
|
||||
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
|
||||
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@ It presents a classic object-oriented UI API that controls a dumb browser. With
|
|||
|
||||
## Try it Online
|
||||
|
||||
Head on over to [http://ooui.mecha.parts:8080/shared-button](http://ooui.mecha.parts:8080/shared-button) and give it a click!
|
||||
Head on over to [http://ooui.mecha.parts](http://ooui.mecha.parts) to tryout the samples.
|
||||
|
||||
|
||||
## Try the Samples Locally
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
public class BoxViewClockSample : ISample
|
||||
{
|
||||
public string Title => "Xamarin.Forms BoxViewClock";
|
||||
|
||||
BoxViewClockPage page;
|
||||
|
||||
public Ooui.Element CreateElement ()
|
||||
{
|
||||
//
|
||||
// Always return the same page because the code never stops the timer
|
||||
// and we don't want to create an unlimited number of them.
|
||||
//
|
||||
if (page == null)
|
||||
page = new BoxViewClockPage ();
|
||||
return page.GetOouiElement ();
|
||||
}
|
||||
|
||||
class BoxViewClockPage : ContentPage
|
||||
{
|
||||
// Structure for storing information about the three hands.
|
||||
struct HandParams
|
||||
{
|
||||
public HandParams (double width, double height, double offset) : this ()
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
Offset = offset;
|
||||
}
|
||||
|
||||
public double Width { private set; get; } // fraction of radius
|
||||
public double Height { private set; get; } // ditto
|
||||
public double Offset { private set; get; } // relative to center pivot
|
||||
}
|
||||
|
||||
static readonly HandParams secondParams = new HandParams (0.02, 1.1, 0.85);
|
||||
static readonly HandParams minuteParams = new HandParams (0.05, 0.8, 0.9);
|
||||
static readonly HandParams hourParams = new HandParams (0.125, 0.65, 0.9);
|
||||
|
||||
BoxView[] tickMarks = new BoxView[60];
|
||||
BoxView secondHand, minuteHand, hourHand;
|
||||
|
||||
public BoxViewClockPage ()
|
||||
{
|
||||
AbsoluteLayout absoluteLayout = new AbsoluteLayout ();
|
||||
|
||||
// Create the tick marks (to be sized and positioned later)
|
||||
for (int i = 0; i < tickMarks.Length; i++) {
|
||||
tickMarks[i] = new BoxView {
|
||||
Color = Color.Accent
|
||||
};
|
||||
absoluteLayout.Children.Add (tickMarks[i]);
|
||||
}
|
||||
|
||||
// Create the three hands.
|
||||
absoluteLayout.Children.Add (hourHand =
|
||||
new BoxView {
|
||||
Color = Color.Accent
|
||||
});
|
||||
absoluteLayout.Children.Add (minuteHand =
|
||||
new BoxView {
|
||||
Color = Color.Accent
|
||||
});
|
||||
absoluteLayout.Children.Add (secondHand =
|
||||
new BoxView {
|
||||
Color = Color.Accent
|
||||
});
|
||||
|
||||
Content = absoluteLayout;
|
||||
|
||||
// Attach a couple event handlers.
|
||||
Device.StartTimer (TimeSpan.FromMilliseconds (16), OnTimerTick);
|
||||
SizeChanged += OnPageSizeChanged;
|
||||
}
|
||||
|
||||
void OnPageSizeChanged (object sender, EventArgs args)
|
||||
{
|
||||
// Size and position the 12 tick marks.
|
||||
Point center = new Point (this.Width / 2, this.Height / 2);
|
||||
double radius = 0.45 * Math.Min (this.Width, this.Height);
|
||||
|
||||
for (int i = 0; i < tickMarks.Length; i++) {
|
||||
double size = radius / (i % 5 == 0 ? 15 : 30);
|
||||
double radians = i * 2 * Math.PI / tickMarks.Length;
|
||||
double x = center.X + radius * Math.Sin (radians) - size / 2;
|
||||
double y = center.Y - radius * Math.Cos (radians) - size / 2;
|
||||
AbsoluteLayout.SetLayoutBounds (tickMarks[i], new Rectangle (x, y, size, size));
|
||||
|
||||
tickMarks[i].AnchorX = 0.51; // Anchor settings necessary for Android
|
||||
tickMarks[i].AnchorY = 0.51;
|
||||
tickMarks[i].Rotation = 180 * radians / Math.PI;
|
||||
}
|
||||
|
||||
// Function for positioning and sizing hands.
|
||||
Action<BoxView, HandParams> Layout = (boxView, handParams) => {
|
||||
double width = handParams.Width * radius;
|
||||
double height = handParams.Height * radius;
|
||||
double offset = handParams.Offset;
|
||||
|
||||
AbsoluteLayout.SetLayoutBounds (boxView,
|
||||
new Rectangle (center.X - 0.5 * width,
|
||||
center.Y - offset * height,
|
||||
width, height));
|
||||
|
||||
boxView.AnchorX = 0.51;
|
||||
boxView.AnchorY = handParams.Offset;
|
||||
};
|
||||
|
||||
Layout (secondHand, secondParams);
|
||||
Layout (minuteHand, minuteParams);
|
||||
Layout (hourHand, hourParams);
|
||||
}
|
||||
|
||||
bool OnTimerTick ()
|
||||
{
|
||||
// Set rotation angles for hour and minute hands.
|
||||
DateTime dateTime = DateTime.Now;
|
||||
hourHand.Rotation = 30 * (dateTime.Hour % 12) + 0.5 * dateTime.Minute;
|
||||
minuteHand.Rotation = 6 * dateTime.Minute + 0.1 * dateTime.Second;
|
||||
|
||||
// Do an animation for the second hand.
|
||||
double t = dateTime.Millisecond / 1000.0;
|
||||
if (t < 0.5) {
|
||||
t = 0.5 * Easing.SpringIn.Ease (t / 0.5);
|
||||
}
|
||||
else {
|
||||
t = 0.5 * (1 + Easing.SpringOut.Ease ((t - 0.5) / 0.5));
|
||||
}
|
||||
secondHand.Rotation = 6 * (dateTime.Second + t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,11 +5,14 @@ namespace Samples
|
|||
{
|
||||
public class ButtonSample : ISample
|
||||
{
|
||||
public string Title => "Button that count clicks";
|
||||
public string Title => "Button Counter";
|
||||
|
||||
Button MakeButton ()
|
||||
{
|
||||
var button = new Button ("Click me!");
|
||||
var button = new Button ("Click me!") {
|
||||
ClassName = "btn btn-primary", // Some bootstrap styling
|
||||
};
|
||||
button.Style.MarginTop = "2em";
|
||||
var count = 0;
|
||||
button.Clicked += (s, e) => {
|
||||
count++;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="ButtonXaml.ButtonXamlPage">
|
||||
|
||||
<StackLayout Padding="20">
|
||||
<Label Text="Welcome to Xamarin.Forms!"/>
|
||||
<Label x:Name="LabelCount" Text="Click Count: 0"/>
|
||||
<Button Text="Tap for click count!"
|
||||
Clicked="OnButtonClicked" />
|
||||
</StackLayout>
|
||||
</ContentPage>
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace ButtonXaml
|
||||
{
|
||||
public partial class ButtonXamlPage
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
public ButtonXamlPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void OnButtonClicked(object sender, EventArgs args)
|
||||
{
|
||||
count++;
|
||||
LabelCount.Text = $"Click Count: {count}";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using Ooui;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
public class ButtonXamlSample : ISample
|
||||
{
|
||||
public string Title => "Xamarin.Forms Button XAML";
|
||||
|
||||
public Ooui.Element CreateElement ()
|
||||
{
|
||||
var page = new ButtonXaml.ButtonXamlPage ();
|
||||
return page.GetOouiElement ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Samples.DisplayAlertPage">
|
||||
<ContentPage.Content>
|
||||
<StackLayout>
|
||||
<Label Text="Welcome to DisplayAlert Sample!" />
|
||||
<Button Text="Tap for Display Alert"
|
||||
Clicked="OnButtonClicked" />
|
||||
</StackLayout>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
|
@ -0,0 +1,23 @@
|
|||
using Ooui;
|
||||
using System;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class DisplayAlertPage : ContentPage
|
||||
{
|
||||
public DisplayAlertPage ()
|
||||
{
|
||||
InitializeComponent ();
|
||||
}
|
||||
|
||||
public async void OnButtonClicked(object sender, EventArgs args)
|
||||
{
|
||||
var result = await DisplayAlert("Alert Message", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.", "YES", "NO");
|
||||
await DisplayAlert("Alert Response", $"You selected value: {result}", "OK");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using Ooui;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
public class DisplayAlertSample : ISample
|
||||
{
|
||||
public string Title => "Xamarin.Forms DisplayAlert";
|
||||
|
||||
public Ooui.Element CreateElement ()
|
||||
{
|
||||
var page = new DisplayAlertPage ();
|
||||
return page.GetOouiElement ();
|
||||
}
|
||||
|
||||
public void Publish ()
|
||||
{
|
||||
UI.Publish ("/display-alert", CreateElement);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace Samples
|
|||
{
|
||||
public class DrawSample : ISample
|
||||
{
|
||||
public string Title => "Collaborative Drawing";
|
||||
public string Title => "Drawing";
|
||||
|
||||
public void Publish ()
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ namespace Samples
|
|||
public Element CreateElement ()
|
||||
{
|
||||
var heading = new Heading ("Draw");
|
||||
var subtitle = new Paragraph ("Click to draw a collaborative masterpiece");
|
||||
var subtitle = new Paragraph ("Click to draw a masterpiece");
|
||||
var canvas = new Canvas {
|
||||
Width = 320,
|
||||
Height = 240,
|
||||
|
|
|
@ -6,7 +6,7 @@ using Ooui;
|
|||
|
||||
namespace Samples
|
||||
{
|
||||
public class FilesSample : ISample
|
||||
public class FilesSample //: ISample
|
||||
{
|
||||
public string Title => "Upload files";
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace Samples
|
|||
{
|
||||
static void Main (string[] args)
|
||||
{
|
||||
Xamarin.Forms.Forms.Init ();
|
||||
|
||||
for (var i = 0; i < args.Length; i++) {
|
||||
var a = args[i];
|
||||
switch (args[i]) {
|
||||
|
@ -27,9 +29,9 @@ namespace Samples
|
|||
new TodoSample ().Publish ();
|
||||
new DrawSample ().Publish ();
|
||||
new FilesSample ().Publish ();
|
||||
new XamarinFormsSample ().Publish ();
|
||||
new DisplayAlertSample ().Publish ();
|
||||
|
||||
UI.Present ("/xamarin-forms");
|
||||
UI.Present ("/display-alert");
|
||||
|
||||
Console.ReadLine ();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableDefaultEmbeddedResourceItems>False</EnableDefaultEmbeddedResourceItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ooui\Ooui.csproj" />
|
||||
<ProjectReference Include="..\Ooui.Forms\Ooui.Forms.csproj" />
|
||||
|
@ -8,6 +12,29 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Forms" Version="2.4.0.38779" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="**/*.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Condition=" '$(EnableDefaultCompileItems)' == 'true' " Update="ButtonXamlPage.xaml.cs">
|
||||
<DependentUpon>*.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Condition=" '$(EnableDefaultCompileItems)' == 'true' " Update="DisplayAlertPage.xaml.cs">
|
||||
<DependentUpon>*.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="ButtonXamlPage.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="DisplayAlertPage.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
|
|
|
@ -7,16 +7,7 @@ namespace Samples
|
|||
{
|
||||
public class TodoSample : ISample
|
||||
{
|
||||
public string Title => "Global TODO list";
|
||||
|
||||
List items = new List () {
|
||||
ClassName = "list-group",
|
||||
};
|
||||
|
||||
public TodoSample ()
|
||||
{
|
||||
items.Style.MarginTop = "1em";
|
||||
}
|
||||
public string Title => "Todo List";
|
||||
|
||||
class Item : ListItem
|
||||
{
|
||||
|
@ -48,6 +39,11 @@ namespace Samples
|
|||
|
||||
Element MakeTodo ()
|
||||
{
|
||||
List items = new List () {
|
||||
ClassName = "list-group",
|
||||
};
|
||||
items.Style.MarginTop = "1em";
|
||||
|
||||
var heading = new Heading ("Todo List");
|
||||
var subtitle = new Paragraph ("This is the shared todo list of the world.");
|
||||
var inputForm = new Form {
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using Xamarin.Forms;
|
||||
using Ooui.Forms;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
public class XamarinFormsSample : ISample
|
||||
{
|
||||
public string Title => "Xamarin.Forms Button Counter";
|
||||
|
||||
Page MakePage ()
|
||||
{
|
||||
Forms.Init ();
|
||||
|
||||
var countLabel = new Label {
|
||||
Text = "0",
|
||||
BackgroundColor = Color.Gold,
|
||||
HorizontalOptions = LayoutOptions.Center,
|
||||
};
|
||||
var countButton = new Button {
|
||||
Text = "Increase",
|
||||
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||
};
|
||||
countButton.Clicked += (sender, e) => {
|
||||
var v = int.Parse (countLabel.Text);
|
||||
countLabel.Text = (v + 1).ToString ();
|
||||
};
|
||||
return new ContentPage {
|
||||
Content = new StackLayout {
|
||||
BackgroundColor = Color.Khaki,
|
||||
Children = {
|
||||
new Label {
|
||||
Text = "Hello World!",
|
||||
FontSize = 32,
|
||||
HorizontalOptions = LayoutOptions.Center,
|
||||
},
|
||||
countLabel,
|
||||
countButton,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public void Publish ()
|
||||
{
|
||||
var page = MakePage ();
|
||||
page.Publish ("/xamarin-forms-shared");
|
||||
|
||||
Ooui.UI.Publish ("/xamarin-forms", () => MakePage ().CreateElement ());
|
||||
}
|
||||
|
||||
public Ooui.Element CreateElement ()
|
||||
{
|
||||
return MakePage ().CreateElement ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Ooui Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=HOME=/home/ubuntu
|
||||
WorkingDirectory=/home/ubuntu/Ooui/PlatformSamples/AspNetCoreMvc
|
||||
ExecStart=/usr/bin/dotnet run --no-build --server.urls=http://0.0.0.0:80/
|
||||
Restart=on-abort
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
Loading…
Reference in New Issue