I'm using a Xamarin.Forms grid application to show a couple of html elements as WebViews in the cells of the grid CardGrid:
private async void CreateCardView()
{
CardGrid.Children.Clear();
// idx over all count elements of html snippets
for (idx = 0; idx < count; idx++)
{
string html = AuthoringCard(idx);
RenderingCard(html, idx);
}
}
AuthoringCard() creates the html code snippet.
RenderingCard() creates the WebView inside the grid cell.
private void RenderingCard(string htmlCard, int index)
{
int CardWidth = 300;
int CardHeight = 150;
int CardNoHorizontally = 3;
WebView uiCard = new WebView();
uiCard.HeightRequest = CardHeight - 5;
uiCard.WidthRequest= CardWidth - 5;
uiCard.VerticalOptions = LayoutOptions.Start;
uiCard.HorizontalOptions = LayoutOptions.Center;
uiCard.Margin = new Thickness(0);
uiCard.AutomationId = index.ToString();
uiCard.Focused += Card_Tapped;
uiCard.InputTransparent = false;
var htmlSource1 = new HtmlWebViewSource
{
Html = htmlCard,
};
uiCard.Source = htmlSource1;
CardGrid.Children.Add(uiCard);
int row = (int)Math.Floor((double)(index / CardNoHorizontally));
int column = index - (row * CardNoHorizontally);
Grid.SetRow(uiCard, row);
Grid.SetColumn(uiCard, column);
}
I want to catch the Focused event, when the user it tapping on the card (WebView) and using the AutomationId to get the index of the card (html code snippet):
private void Card_Tapped(object sender, EventArgs e)
{
WebView card = (WebView)sender;
int index = Convert.ToInt16(card.AutomationId));
}
This works fine with Android. Under iOS the event is never raised. Any idea for a solution?
Cause:
the property Focus in Forms correspond method that we called becomeFirstResponder in native iOS platform.Unfortunately,UIWebView and WKwebview do not support the method becomeFirstResponder.This method is only available in some 'input-controls' Such as UITextField and UITextView(Entry in Forms).So even if you set the event on a webview.It will not work in iOS.
Workaround:
You can add a TapGestureRecognizer on the webview.And you have to implement it by using CustomRenderer.Because it will create conflict if you add TapGestureRecognizer in forms.
Refer to the following code.
in Forms
public MainPage()
{
if (Device.RuntimePlatform == "iOS")
{
MessagingCenter.Subscribe<Object,string>(this,"webview_click", (sender,arg)=> {
// int index = Convert.ToInt16(arg));
});
}
}
in iOS
using System;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx;
using xxx.iOS;
using ObjCRuntime;
[assembly:ExportRenderer(typeof(WebView),typeof(MyWebViewRenderer))]
namespace xxx.iOS
{
public class MyWebViewRenderer : WebViewRenderer, IUIGestureRecognizerDelegate
{
public bool isFirstLoad = true;
public MyWebViewRenderer()
{
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e != null)
{
UITapGestureRecognizer tap = new UITapGestureRecognizer(this, new Selector("Tap_Handle:"));
tap.WeakDelegate = this;
this.AddGestureRecognizer(tap);
}
}
[Export("gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:")]
public bool ShouldRecognizeSimultaneously(UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer)
{
return true;
}
[Export("Tap_Handle:")]
void Tap_Handle(UITapGestureRecognizer tap)
{
if(isFirstLoad)
{
isFirstLoad = false;
MessagingCenter.Send<Object,string>(this, "webview_click",Element.AutomationId);
}
}
}
}
I am trying to use Mouse.GetState() for my menu selection. Currently, it will only highlight if I hover over a region left and up from where the menu is. I used DrawString to display the mouses coordinates and found that the 0,0 point wasn't in the top left of my monitor or in the top left of the game window. It was somewhere about 100,100 pixels from the top left of the screen. Also, the 0,0 point moves every time I run the programme.
I looked at others people who have had the same problem but wasn't able to solve it. I tried using Mouse.WindowHandle = this.Window.Handle; in my Initialize() but it didn't nothing. I have two monitors and when I forced the game in fullscreen it would open on my second monitor so I disabled it but the problem remains.
here is a link to my code http://pastebin.com/PNaFADqp
Game1 class:
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont spriteFont;
public const int WINDOW_HEIGHT = 800;
public const int WINDOW_WIDTH = 600;
public int tree;
public TitleScreen titleScreen;
public SATDemo satDemo;
public SeparatingAxisTest separatingAxisTest;
public SATWithAABB sATWithAABB;
GameState currentState;
public static Dictionary<string, Texture2D> m_textureLibrary = new Dictionary<string, Texture2D>();
public static Dictionary<string, SpriteFont> m_fontLibrary = new Dictionary<string, SpriteFont>();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferHeight = WINDOW_HEIGHT;
graphics.PreferredBackBufferWidth = WINDOW_WIDTH;
}
protected override void Initialize()
{
Mouse.WindowHandle = this.Window.Handle;
//enable the mousepointer
IsMouseVisible = true;
currentState = GameState.TitleScreen;
//sets the windows mouse handle to client bounds handle
base.Initialize();
}
public void RequestSATDemo()
{
currentState = GameState.RequestSATDemo;
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
m_textureLibrary.Add("Pixel", Content.Load<Texture2D>("White_Pixel"));
m_fontLibrary.Add("Font", Content.Load<SpriteFont>("MotorwerkOblique"));
titleScreen = new TitleScreen();
satDemo = new SATDemo();
separatingAxisTest = new SeparatingAxisTest();
sATWithAABB = new SATWithAABB();
}
public void RequestSeparatingAxisTest()
{
currentState = GameState.SeparatingAxisTest;
}
public void RequestSATWithAABB()
{
currentState = GameState.SATWithAABB;
}
protected override void Update(GameTime gameTime)
{
MouseTestState = Mouse.GetState();
switch (currentState)
{
case GameState.TitleScreen:
{
titleScreen.Update(gameTime);
break;
}
case GameState.SeparatingAxisTest:
{
separatingAxisTest.Update(gameTime);
break;
}
case GameState.SATWithAABB:
{
sATWithAABB.Update(gameTime);
break;
}
case GameState.Exit:
{
Exit();
break;
}
default:
{
titleScreen.Update(gameTime);
break;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
spriteBatch.DrawString(m_fontLibrary["Font"], MouseTestState.ToString(), new Vector2(0, 0), Color.White);
switch (currentState)
{
case GameState.TitleScreen:
{
titleScreen.Draw(spriteBatch, spriteFont);
break;
}
case GameState.SeparatingAxisTest:
{
separatingAxisTest.Draw(gameTime, spriteBatch);
break;
}
case GameState.SATWithAABB:
{
sATWithAABB.Draw(gameTime, spriteBatch);
break;
}
case GameState.Exit:
{
Exit();
break;
}
default:
{
titleScreen.Update(gameTime);
break;
}
}
spriteBatch.End();
base.Draw(gameTime);
}
}
TitleScreen class:
public class TitleScreen : Screen
{
List<Button> buttonList = new List<Button>();
public Menu mainMenu;
public TitleScreen()
{
mainMenu = new Menu(new Vector2(200, 100), buttonList, 0);
buttonList.Add(new PushButton("Separating Axis Test"));
buttonList.Add(new PushButton("SAT With AABB"));
buttonList.Add(new PushButton("Awesome"));
buttonList.Add(new PushButton("Awesomere"));
buttonList.Add(new PushButton("Awesomere"));
}
public override void Update(GameTime gametime)
{
mainMenu.Update(gametime);
}
public void Draw(SpriteBatch sB, SpriteFont sF)
{
mainMenu.Draw(sB, sF);
}
}
PushButton class:
public class PushButton : Button
{
string m_text;
SpriteFont m_font;
Color m_static, m_onClick, m_onHover;
Texture2D m_sprite2D, m_onClick2D;
static public int Pbuttoncount;
//click processing
bool m_clickedInside = false,
m_releasedInside = false,
m_OnClicked = false,
selected = false;
Rectangle drawRectangle;
public PushButton(string Text)
{
m_text = Text;
drawRectangle = new Rectangle((int)Menu.m_position.X, (int)Menu.m_position.Y + (15 * Pbuttoncount), 200, 15);
ButtonRegion = new Rectangle((int)Position.X, (int)Position.Y, 200, 15);
Pbuttoncount++;
}
public PushButton(Rectangle ButtonRegion, SpriteFont Font, string Text, Color Static, Color OnClick, Color OnHover)
{
m_buttonRegion = ButtonRegion;
m_font = Font;
m_text = Text;
m_static = Static;
m_onClick = OnClick;
m_onHover = OnHover;
// drawRectangle = ButtonPosition(m_buttonRegion);
}
public PushButton(Rectangle ButtonRegion, Texture2D Sprite2D, Texture2D OnClick2D)
{
m_buttonRegion = ButtonRegion;
m_sprite2D = Sprite2D;
m_onClick2D = OnClick2D;
//drawRectangle = ButtonPosition(m_buttonRegion);
}
public override void Update(GameTime gameTime)
{
MouseState currentMouse = Mouse.GetState();
selected = MouseState(drawRectangle, currentMouse);
m_clickedInside = ClickInside(currentMouse, m_lastMouseState);
ReleaseInside(currentMouse, m_lastMouseState);
if (selected && m_clickedInside && m_releasedInside)
m_OnClicked = true;
else
m_OnClicked = false;
m_lastMouseState = currentMouse;
}
public override void Draw(SpriteBatch spriteBatch, SpriteFont spriteFont, int buttonCount, Vector2 Position)
{
spriteBatch.Draw(Game1.m_textureLibrary["Pixel"], new Rectangle((int)Position.X + 10, (int)(Position.Y + 15 * buttonCount), 180, 15), Color.Wheat);
if (selected)
spriteBatch.DrawString(Game1.m_fontLibrary["Font"], m_text, new Vector2(Position.X + 15, Position.Y + 15 * buttonCount), Color.Orange);
else
spriteBatch.DrawString(Game1.m_fontLibrary["Font"], m_text, new Vector2(Position.X + 15, Position.Y + 15 * buttonCount), Color.Black);
}
}
Menu class:
public class Menu
{
List<Button> m_buttonList;
float m_transparency;
public int n = 0;
public Rectangle buttonRegion, m_menuRegion, m_dimensions;
static public Vector2 m_position;
int m_WINDOW_HEIGHT = Game1.WINDOW_HEIGHT;
int m_WINDOW_WIDTH = Game1.WINDOW_WIDTH;
private Game1 m_managerClass;
public Menu(Vector2 Position, List<Button> ButtonList, float Transparency)
{
m_position = Position;
m_buttonList = ButtonList;
m_transparency = Transparency;
m_managerClass = new Game1();
}
public Rectangle MenuRegion
{
get { return m_menuRegion; }
set { m_menuRegion = value; }
}
static public Vector2 Position
{
get { return m_position; }
}
public void Update(GameTime gametime)
{
for (int i = 0; i < m_buttonList.Count; i++)
{
m_buttonList[i].Update(gametime);
if (m_buttonList[0].OnClicked)
{
SeperatingAxisTest();
}
}
}
public void Draw(SpriteBatch sB, SpriteFont sF)
{
sB.Draw(Game1.m_textureLibrary["Pixel"], new Rectangle((int)m_position.X - 5, (int)m_position.Y - 10, (m_buttonList[0].ButtonRegion.Width + 10), (m_buttonList[0].ButtonRegion.Height * m_buttonList.Count) + 20), Color.Blue);
for (int i = 0; i < m_buttonList.Count; i++)
{
m_buttonList[i].Draw(sB, sF, i, new Vector2(Position.X, Position.Y));
}
}
private void SeperatingAxisTest()
{
m_managerClass.RequestSeparatingAxisTest();
}
}
Program class:
public static class Program
{
[STAThread]
static void Main()
{
using (var game = new Game1())
game.Run();
}
}
Let me know if you need anything else. I'm still learning and will sell my soul to you for an answer.
Your Menu class is creating a new instance of Game1. This is, most likely, not what you want, since Game1 is instantiated in the entry point for you app. The Game1 instance has an instance of TitleScreen, which in turn has an instance of the Menu class, so a Menu should have no business creating its own game.
When this (other) instance is created, it invokes platform-specific (Windows) methods, creates an additional window handle (which is never shown) and configures the Mouse.WindowHandle.
And btw, setting WindowHandle manually does absolutely nothing in Monogame, so all these sources mentioning that are talking about XNA.
So, there are several remarks:
You should probably have a "screen manager" class which contains the current screen. It is strange to have a field of type TitleScreen in your game class, it should at least be of the base type (Screen), so that the game class draws and updates each screen transparently.
If you need a reference to the game class anywhere, don't instantiate a new one, but rather pass it along through the constructor.
m_managerClass is a bad name for a field which is actually a Game. Also google for C# naming conventions. Perhaps you even might want to download an existing monogame game template, e.g. check some of the samples online; the NetRumble sample seems to implement a screen manager.
Remove the Mouse.WindowHandle line, it should be set to your one-and-only game window by default.
tl;dr add the Game1 as a parameter wherever you might need it (but only where you need it).
abstract class Screen
{
private readonly Game1 _game;
public Game1 Game
{ get { return _game; } }
public Screen(Game1 game)
{
_game = game;
}
}
class TitleScreen : Screen
{
public TitleScreen(Game1 game)
: base(game)
{ ... }
}
class Menu
{
private readonly Screen _screen;
public Menu(Screen parentScreen, Vector2 pos, List<Button> list, float alpha)
{
_screen = parentScreen;
...
// if you need the game instance, just use _screen.Game
}
}
How can I draw a line on a bitmap in Stage3D using Agal? Can someone provide a code example?
If you use Starling you can try this:
/**
* Class Line
* #author Leandro Barreto 2012
* #version 1.0
**/
package starling.utils
{
import starling.display.Quad;
import starling.display.Sprite;
public class Line extends Sprite
{
private var baseQuad:Quad;
private var _thickness:Number = 1;
private var _color:uint = 0x000000;
public function Line()
{
baseQuad = new Quad(1, _thickness, _color);
addChild(baseQuad);
}
public function lineTo(toX:int, toY:int):void
{
baseQuad.width = Math.round(Math.sqrt((toX*toX)+(toY*toY)));
baseQuad.rotation = Math.atan2(toY, toX);
}
public function set thickness(t:Number):void
{
var currentRotation:Number = baseQuad.rotation;
baseQuad.rotation = 0;
baseQuad.height = _thickness = t;
baseQuad.rotation = currentRotation;
}
public function get thickness():Number
{
return _thickness;
}
public function set color(c:uint):void
{
baseQuad.color = _color = c;
}
public function get color():uint
{
return _color;
}
}
}
Someone suggested at the Starling forums that we create a Line class which draws a few quads connecting two points. This tutorial shows how to create polygons using AGAL for shaders:
http://wiki.starling-framework.org/manual/custom_display_objects
I recently wrote a simple library to draw lines on Stage3D.
It's called Zebroid, https://github.com/luwes/Zebroid
Zebroid does not support line caps or joints yet.
I'm currently doing an assignment, on which one of the requirements is for a random object to appear on screen and move across. Being new to XNA, i do not know where to even begin implementing such behaviours to the game, thus would really appreciate if someone could give me a nudge towards the right direction.
I'm only really accustomed to invoking something when a key is pressed, however with something completely random, this can't be done. as far as i am aware of.
Thank you.
You need to create and set up a sprite for the UFO first. In your protected override void Update(GameTime gameTime) code you simply need to get the current time and compare it to the rules in which you wish to apply. Then update if you wish to draw and "move" the sprite. Here is an example:
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion
public class Game : Microsoft.Xna.Framework.Game {
#region Game Settings
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
GraphicsDevice device;
int screenWidth = 800;
int screenHeight = 600;
bool fullscreen = false;
string title = "MyGame";
string origionaltitle;
float frames = 0;
float framesPerSecond = 0;
int startTime;
int currentTime;
int nextTime;
#endregion
struct sprite {
public string TextureName;
public Texture2D Texture;
public Vector2 Position;
public Vector2 Speed;
public Color[] TextureData;
};
bool DrawUFO = false;
sprite ufo = new sprite();
public Game() {
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void LoadContent() {
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
device = graphics.GraphicsDevice;
// TODO: use this.Content to load your game content here
ufo.TextureName = "ufo";
ufo.Texture = Content.Load<Texture2D>(ball.TextureName);
ufo.TextureData = new Color[ufo.Texture.Width *ufo.Texture.Height];
ufo.Texture.GetData(ball.TextureData);
}
protected override void Initialize() {
// TODO: Add your initialization logic here
ufo.Position = new Vector2(10f, 10.0f);
ufo.Speed = new Vector2(0.0f, 10.0f);
//
// Set up game window
graphics.PreferredBackBufferWidth = screenWidth;
graphics.PreferredBackBufferHeight = screenHeight;
graphics.IsFullScreen = fullscreen;
graphics.ApplyChanges();
origionaltitle = title;
Window.Title = title;
//
// Set the initial time
startTime = DateTime.Now.Second;
//
// Set "random"/next time for ufo to be rendered
nextTime = startTime + rand.Next(2);
//
base.Initialize();
}
protected override void Update(GameTime gameTime) {
//
// Set the current time
currentTime = DateTime.Now.Second;
//
// if not drawing ufo then
if(!DrawURO) {
//
// check current time and compare it with the next time
if( currentTime == nextTime ) {
DrawURO = true;
}
} else {
//
// Update UFO position (aka move it)
ufo.Posistion += ball.Speed *(float)gameTime.ElapsedGameTime.TotalSeconds;
//
// if ufo goes of the screen then
if(ufo.Position.Y > screenHeight) {
//
// Reset ufo
DrawURO = false;
ufo.Position.X = 10.0f;
ufo.Position.Y = 10.0f;
//
// set next time to render
nextTime = currentTime + rand.Next(2);
}
}
}
protected override void Draw(GameTime gameTime) {
graphics.GraphicsDevice.Clear(Color.Black);
// TODO: Add your drawing code here
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
if(DrawUFO == true) {
spriteBatch.Draw(ufo.Texture, ufo.Position, Color.White);
}
spriteBatch.End();
//
base.Draw(gameTime);
}
}
I copied this from some code i did at college a few years a ago, so apologies for any bugs.
I've been reading about Vala over the past couple of days and decided to dive into it and make some Clutter widgets along the way. I'm currently trying to draw a private actor from my custom actor subclass. Here is a simplified version of what I've got so far.
public class MyContainer : Clutter.Actor, Clutter.Container {
private Clutter.Group group;
public MyContainer() {
group = new Clutter.Group();
group.set_parent(this);
}
public void add_actor(Clutter.Actor actor) {
group.add_actor(actor);
actor.show();
set_size(group.width, group.height);
actor_added(actor);
queue_redraw();
}
public void foreach(Clutter.Callback callback) {
group.foreach(callback);
queue_redraw();
}
public override void get_preferred_height(
float for_width,
out float min_height_p,
out float natural_height_p) {
group.get_preferred_height(
for_width,
out min_height_p,
out natural_height_p);
}
public override void get_preferred_width(
float for_height,
out float min_width_p,
out float natural_width_p) {
group.get_preferred_width(
for_height,
out min_width_p,
out natural_width_p);
}
public override void paint() {
group.paint();
}
public void remove_actor(Clutter.Actor actor) {
group.remove_actor(actor);
set_size(group.width, group.height);
actor_removed(actor);
queue_redraw();
}
public void sort_depth_order() {
group.sort_depth_order();
queue_redraw();
}
}
int main(string [] args) {
// Start clutter.
var result = Clutter.init(ref args);
if (result != Clutter.InitError.SUCCESS) {
stderr.printf("Error: %s\n", result.to_string());
return 1;
}
var stage = Clutter.Stage.get_default();
// Build a MyCollection object.
var myc = new MyContainer();
myc.x = 100;
myc.y = 100;
var r1 = new Clutter.Rectangle();
r1.width = 50;
r1.height = 50;
r1.color = Clutter.Color.from_string("rgb(255, 0, 0)");
var t1 = new Clutter.Text();
t1.text = "The red square.";
t1.y = r1.height;
// Build a Group object similar to the previous.
var group = new Clutter.Group();
group.x = 300;
group.y = 100;
var r2 = new Clutter.Rectangle();
r2.width = 50;
r2.height = 50;
r2.color = Clutter.Color.from_string("rgb(255, 0, 0)");
var t2 = new Clutter.Text();
t2.text = "The red square.";
t2.y = r2.height;
// Display.
myc.add_actor(r1);
myc.add_actor(t1);
group.add_actor(r2);
group.add_actor(t2);
stage.add_actor(myc);
stage.add_actor(group);
stage.show_all();
Clutter.main();
return 0;
}
The example paints the group added directly to the stage, but not the group wrapped by the custom collection that is added to the stage. How can I get this to work and what is wrong with the above?
I've been working on ubuntu 11.10 with valac --pkg clutter-1.0 above_code_example.vala.
This answer is from buz on gnome.irc's #clutter room.
The problem is a missing override for the allocate function.