Custom container not drawing - vala

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.

Related

keeping track of a series of simple multiple choice web form answers

This is the code I'm trying to use, which seems logical. But doesn't seem to be working.
MyAsFileName.prototype.getTotalScore = function() {
var totalScore = 0;
for (var i = 0; i < allQuestions.length; i++) {
totalScore += allQuestions[i].getCalculatedScore();
if (currentModule.allQuestions[i].parent.questionCorrect == true) {
knowledgePoints++;
} else {
knowledgePoints--;
}
}
debugLog("Total score: " + totalScore);
debugLog(knowledgePoints);
return totalScore;
}
I have allQuestions defined as below:
var allQuestions = Array();
I have knowledgePoints defined as:
this.knowledgePoints = 10;
I have questionCorrect defined as:
this.questionCorrect = false;
Second fresh attempt made with new class as answer below suggested (commented out for now until I figure out how to get working):
// package
// {
/*public class Quiz {
//public
var knowledgePoints: int = 10;
//public
var allQuestions: Array = new Array;
//public
var questionCorrect: Boolean = false;
//public
function getTotalScore(): int {
var totalScore: int = 0;
for (var i = 0; i < allQuestions.length; i++) {
totalScore += allQuestions[i].getCalculatedScore();
if (currentModule.allQuestions[i].parent.questionCorrect) {
knowledgePoints++;
} else {
knowledgePoints--;
}
}
debugLog("Total score: " + totalScore);
debugLog(knowledgePoints);
return totalScore;
}
}*/
//}
This code above outputs two errors in flash console:
Error 1. Attribute used outside of class.
Error 2. 'Int' could not be loaded.
It's a weird (and actually non-AS3 way) way to do this. Instead of creating a unnamed closure which refers weird variables from who-knows where, you should make it a normal AS3 class, something like that (in a file named Quiz.as):
package
{
public class Quiz
{
public var knowledgePoints:int = 10;
public var allQuestions:Array = new Array;
public var questionCorrect:Boolean = false;
public function getTotalScore():int
{
var totalScore:int = 0;
// Your code does not explain how you will that Array.
// It is initially an empty Array of length 0.
for (var i = 0; i < allQuestions.length; i++)
{
totalScore += allQuestions[i].getCalculatedScore();
if (currentModule.allQuestions[i].parent.questionCorrect)
{
knowledgePoints++;
}
else
{
knowledgePoints--;
}
}
// Not sure what it is.
debugLog("Total score: " + totalScore);
debugLog(knowledgePoints);
return totalScore;
}
}
}

Set bindings for custom DependencyObjects

This is a continuation of a question here: Trying to setup a custom DependencyObject. Clearly missing something. It's not practical to edit the original question; changes are too great. So I'm starting a fresh question.
I'm trying to setup bindings between custom DependencyObjects in my UWP app. The relevant code is below. I am seeing calls to ActualWidthPropertyChanged, but they are not triggering any call to WidthPropertyChanged. What am I missing?
class WindowsElement: DependencyObject
{
public WindowsElement()
{
}
public double Width
{
get
{
return (double)GetValue(WidthProperty);
}
set
{
SetValue(WidthProperty, value);
}
}
private static void WidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
WindowsElement element = (WindowsElement)o;
double width = (double)e.NewValue;
CommonDebug.LogLine("WPC", element, o, width);
element.Width = width;
}
private static void ActualWidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
WindowsElement element = (WindowsElement)o;
double width = (double)e.NewValue;
CommonDebug.LogLine("AWPC", o, e, width, element.Width);
element.ActualWidth = width;
}
public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
"Width",
typeof(double),
typeof(WindowsElement),
new PropertyMetadata((double)0, WidthPropertyChanged));
public double ActualWidth {
get
{
return (double)GetValue(ActualWidthProperty);
}
set
{
SetValue(ActualWidthProperty, value);
}
}
public static readonly DependencyProperty ActualWidthProperty =
DependencyProperty.Register(
"ActualWidth",
typeof(double),
typeof(WindowsElement),
new PropertyMetadata((double)0, ActualWidthPropertyChanged));
public static void MessWithBindings()
{
WindowsElement we1 = new WindowsElement();
WindowsElement we2 = new WindowsElement();
var b = new Binding
{
Source = we2,
Path = new PropertyPath("ActualWidth")
};
BindingOperations.SetBinding(we1, WindowsElement.WidthProperty, b);
we2.ActualWidth = 13;
CommonDebug.LogLine(we1, we1.Width, we1.ActualWidth, we2, we2.Width, we2.ActualWidth);
}
}
I am seeing calls to ActualWidthPropertyChanged, but they are not triggering any call to WidthPropertyChanged. What am I missing?
To solve this question, you would need to implement the INotifyPropertyChanged interface on the source object so that the source can report changes.
Please see the following code:
class WindowsElement : DependencyObject, INotifyPropertyChanged
{
public WindowsElement()
{
}
public double Width
{
get
{
return (double)GetValue(WidthProperty);
}
set
{
SetValue(WidthProperty, value);
}
}
private static void WidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
WindowsElement element = (WindowsElement)o;
double width = (double)e.NewValue;
CommonDebug.LogLine("WPC", element, o, width);
//element.Width = width;
element.RaisedPropertyChanged("Width");
}
private static void ActualWidthPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
WindowsElement element = (WindowsElement)o;
double width = (double)e.NewValue;
CommonDebug.LogLine("AWPC", o, e, width, element.Width);
//element.ActualWidth = width;
element.RaisedPropertyChanged("ActualWidth");
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisedPropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
"Width",
typeof(double),
typeof(WindowsElement),
new PropertyMetadata((double)0, WidthPropertyChanged));
public double ActualWidth
{
get
{
return (double)GetValue(ActualWidthProperty);
}
set
{
SetValue(ActualWidthProperty, value);
}
}
public static readonly DependencyProperty ActualWidthProperty = DependencyProperty.Register(
"ActualWidth",
typeof(double),
typeof(WindowsElement),
new PropertyMetadata((double)0, ActualWidthPropertyChanged));
public static void MessWithBindings()
{
WindowsElement we1 = new WindowsElement();
WindowsElement we2 = new WindowsElement();
var b = new Binding
{
Source = we2,
Path = new PropertyPath("ActualWidth")
};
BindingOperations.SetBinding(we1, WindowsElement.WidthProperty, b);
we2.ActualWidth = 13;
CommonDebug.LogLine(we1, we1.Width, we1.ActualWidth, we2, we2.Width, we2.ActualWidth);
}
}
Not sure why in UWP a one-way Binding from one dependency property to another doesn't automatically update the target property (as it does in WPF).
However, you could simply revert the direction of the Binding and make it two-way:
var b = new Binding
{
Source = we1,
Path = new PropertyPath("Width"),
Mode = BindingMode.TwoWay
};
BindingOperations.SetBinding(we2, WindowsElement.ActualWidthProperty, b);
we2.ActualWidth = 13;

MonoGame/XNA Mouse Offsets

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
}
}

Xna (MonoGame) DynamicSoundEffectInstance Buffer already Full exception

I'm making this game in MonoGame (basically Xna) that uses DynamicSoundEffectInstance class. MonoGame does not have an implementation of DynamicSoundEffectInstance yet, so I made my own:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if MONOMAC
using MonoMac.OpenAL;
#else
using OpenTK.Audio.OpenAL;
#endif
using System.Threading;
namespace Microsoft.Xna.Framework.Audio
{
public sealed class DynamicSoundEffectInstance : IDisposable
{
private const int BUFFERCOUNT = 2;
private SoundState soundState = SoundState.Stopped;
private AudioChannels channels;
private int sampleRate;
private ALFormat format;
private bool looped = false;
private float volume = 1.0f;
private float pan = 0;
private float pitch = 0f;
private int sourceId;
private int[] bufferIds;
private int[] bufferIdsToFill;
private int currentBufferToFill;
private bool isDisposed = false;
private bool hasSourceId = false;
private Thread bufferFillerThread = null;
// Events
public event EventHandler<EventArgs> BufferNeeded;
internal void OnBufferNeeded(EventArgs args)
{
if (BufferNeeded != null)
{
BufferNeeded(this, args);
}
}
public DynamicSoundEffectInstance(int sampleRate, AudioChannels channels)
{
this.sampleRate = sampleRate;
this.channels = channels;
switch (channels)
{
case AudioChannels.Mono:
this.format = ALFormat.Mono16;
break;
case AudioChannels.Stereo:
this.format = ALFormat.Stereo16;
break;
default:
break;
}
}
public bool IsDisposed
{
get
{
return isDisposed;
}
}
public float Pan
{
get
{
return pan;
}
set
{
pan = value;
if (hasSourceId)
{
// Listener
// Pan
AL.Source(sourceId, ALSource3f.Position, pan, 0.0f, 0.1f);
}
}
}
public float Pitch
{
get
{
return pitch;
}
set
{
pitch = value;
if (hasSourceId)
{
// Pitch
AL.Source(sourceId, ALSourcef.Pitch, XnaPitchToAlPitch(pitch));
}
}
}
public float Volume
{
get
{
return volume;
}
set
{
volume = value;
if (hasSourceId)
{
// Volume
AL.Source(sourceId, ALSourcef.Gain, volume * SoundEffect.MasterVolume);
}
}
}
public SoundState State
{
get
{
return soundState;
}
}
private float XnaPitchToAlPitch(float pitch)
{
// pitch is different in XNA and OpenAL. XNA has a pitch between -1 and 1 for one octave down/up.
// openAL uses 0.5 to 2 for one octave down/up, while 1 is the default. The default value of 0 would make it completely silent.
return (float)Math.Exp(0.69314718 * pitch);
}
public void Play()
{
if (!hasSourceId)
{
bufferIds = AL.GenBuffers(BUFFERCOUNT);
sourceId = AL.GenSource();
hasSourceId = true;
}
soundState = SoundState.Playing;
if (bufferFillerThread == null)
{
bufferIdsToFill = bufferIds;
currentBufferToFill = 0;
OnBufferNeeded(EventArgs.Empty);
bufferFillerThread = new Thread(new ThreadStart(BufferFiller));
bufferFillerThread.Start();
}
AL.SourcePlay(sourceId);
}
public void Apply3D(AudioListener listener, AudioEmitter emitter)
{
Apply3D(new AudioListener[] { listener }, emitter);
}
public void Pause()
{
if (hasSourceId)
{
AL.SourcePause(sourceId);
soundState = SoundState.Paused;
}
}
public void Apply3D(AudioListener[] listeners, AudioEmitter emitter)
{
// get AL's listener position
float x, y, z;
AL.GetListener(ALListener3f.Position, out x, out y, out z);
for (int i = 0; i < listeners.Length; i++)
{
AudioListener listener = listeners[i];
// get the emitter offset from origin
Vector3 posOffset = emitter.Position - listener.Position;
// set up orientation matrix
Matrix orientation = Matrix.CreateWorld(Vector3.Zero, listener.Forward, listener.Up);
// set up our final position and velocity according to orientation of listener
Vector3 finalPos = new Vector3(x + posOffset.X, y + posOffset.Y, z + posOffset.Z);
finalPos = Vector3.Transform(finalPos, orientation);
Vector3 finalVel = emitter.Velocity;
finalVel = Vector3.Transform(finalVel, orientation);
// set the position based on relative positon
AL.Source(sourceId, ALSource3f.Position, finalPos.X, finalPos.Y, finalPos.Z);
AL.Source(sourceId, ALSource3f.Velocity, finalVel.X, finalVel.Y, finalVel.Z);
}
}
public void Dispose()
{
if (!isDisposed)
{
Stop(true);
AL.DeleteBuffers(bufferIds);
AL.DeleteSource(sourceId);
bufferIdsToFill = null;
hasSourceId = false;
isDisposed = true;
}
}
public void Stop()
{
if (hasSourceId)
{
AL.SourceStop(sourceId);
int pendingBuffers = PendingBufferCount;
if(pendingBuffers > 0)
AL.SourceUnqueueBuffers(sourceId, PendingBufferCount);
if (bufferFillerThread != null)
bufferFillerThread.Abort();
bufferFillerThread = null;
}
soundState = SoundState.Stopped;
}
public void Stop(bool immediate)
{
Stop();
}
public TimeSpan GetSampleDuration(int sizeInBytes)
{
throw new NotImplementedException();
}
public int GetSampleSizeInBytes(TimeSpan duration)
{
int size = (int)(duration.TotalMilliseconds * ((float)sampleRate / 1000.0f));
return (size + (size & 1)) * 16;
}
public void SubmitBuffer(byte[] buffer)
{
this.SubmitBuffer(buffer, 0, buffer.Length);
}
public void SubmitBuffer(byte[] buffer, int offset, int count)
{
if (bufferIdsToFill != null) {
AL.BufferData (bufferIdsToFill [currentBufferToFill], format, buffer, count, sampleRate);
AL.SourceQueueBuffer (sourceId, bufferIdsToFill [currentBufferToFill]);
currentBufferToFill++;
if (currentBufferToFill >= bufferIdsToFill.Length)
bufferIdsToFill = null;
else
OnBufferNeeded (EventArgs.Empty);
} else {
throw new Exception ("Buffer already full.");
}
}
private void BufferFiller()
{
bool done = false;
while (!done)
{
var state = AL.GetSourceState(sourceId);
if (state == ALSourceState.Stopped || state == ALSourceState.Initial)
AL.SourcePlay(sourceId);
if (bufferIdsToFill != null)
continue;
int buffersProcessed;
AL.GetSource(sourceId, ALGetSourcei.BuffersProcessed, out buffersProcessed);
if (buffersProcessed == 0)
continue;
bufferIdsToFill = AL.SourceUnqueueBuffers(sourceId, buffersProcessed);
currentBufferToFill = 0;
OnBufferNeeded(EventArgs.Empty);
}
}
public bool IsLooped
{
get
{
return looped;
}
set
{
looped = value;
}
}
public int PendingBufferCount
{
get
{
if (hasSourceId)
{
int buffersQueued;
AL.GetSource(sourceId, ALGetSourcei.BuffersQueued, out buffersQueued);
return buffersQueued;
}
return 0;
}
}
}
}
Now, I followed this tutorial on making dynamic sounds in Xna, which worked with my custom MonoGame class. However, when I run the project (Xamarin Studio 4, Mac OS X 10.8, with MonoGame 3.0.1), it throws this exception:
Buffer already full
Pointing at the code in my custom class:
public void SubmitBuffer(byte[] buffer, int offset, int count)
{
if (bufferIdsToFill != null) {
AL.BufferData (bufferIdsToFill [currentBufferToFill], format, buffer, count, sampleRate);
AL.SourceQueueBuffer (sourceId, bufferIdsToFill [currentBufferToFill]);
currentBufferToFill++;
if (currentBufferToFill >= bufferIdsToFill.Length)
bufferIdsToFill = null;
else
OnBufferNeeded (EventArgs.Empty);
} else {
throw new Exception ("Buffer already full."); //RIGHT HERE IS THE EXCEPTION
}
}
I commented out the exception, and ran it again. It played the sound, with pops in it, but it still played it. How can I clear the buffer, so it is not full? I followed this tutorial EXACTLY, so all the code I added to my project is in there.
Oh! Figured it out myself; I changed the pending buffer count from 3 to 2. My final submit buffer code was:
while(_instance.PendingBufferCount < 2)
SubmitBuffer();
Where the 2 is, used to be a 3. Now it no longer throws the exception.

Changing the colour of UIPageControl dots in MonoTouch

I was wondering if MonoTouch allows the developer to change the colour of UIPageControl dots to suit a light background - they seem to be fixed white, which makes them very hard to see on a light textured background.
I am aware there is no public API available for this but I was wondering if anything was internally implemented in MonoTouch to improve on this.
Otherwise, what's the recommended approach to using a UIPageControl on a light background?
I took a stab at translating this. I'm not sure it will work, but it does compile. Note that the page linked to contains comments indicating that Apple frowns upon this code and may reject it:
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace Whatever
{
public class StyledPageControl : UIPageControl
{
public StyledPageControl () : base()
{
}
public override int CurrentPage {
get {
return base.CurrentPage;
}
set {
base.CurrentPage = value;
string imgActive = NSBundle.MainBundle.PathForResource("activeImage", "png");
string imgInactive = NSBundle.MainBundle.PathForResource("inactiveImage", "png");
for (int subviewIndex = 0; subviewIndex < this.Subviews.Length; subviewIndex++)
{
UIImageView subview = this.Subviews[subviewIndex] as UIImageView;
if (subviewIndex == value)
subview.Image = UIImage.FromFile(imgActive);
else
subview.Image = UIImage.FromFile(imgInactive);
}
}
}
public override int Pages {
get {
return base.Pages;
}
set {
base.Pages = value;
string img = NSBundle.MainBundle.PathForResource("inactiveImage", "png");
for (int subviewIndex = 0; subviewIndex < this.Subviews.Length; subviewIndex++)
{
UIImageView subview = this.Subviews[subviewIndex] as UIImageView;
subview.Image = UIImage.FromFile(img);
}
}
}
}
}
Convert the following code to C#: http://apptech.next-munich.com/2010/04/customizing-uipagecontrols-looks.html
I combined this and this for monotouch. I hope this helps.
The usage is like this:
_pager.Change += delegate(object sender, EventArgs e) {
var pc = sender as PageControl;
Console.WriteLine ("Change Delegate== " + pc.currentPage);
var toPage = pc.currentPage;
var pageOffset = _scroll.Frame.Width*toPage;
PointF p = new PointF(pageOffset, 0);
Console.WriteLine (pageOffset);
_scroll.SetContentOffset(p,true);
};
And the class like this.
public class PageControl:UIView
{
#region ctor
public PageControl (RectangleF rect) :base(rect)
{
this.BackgroundColor = UIColor.Red;
this.CurrenColor=new CGColor(.2f,15f,10F);
this.OtherColor =new CGColor(.77F,.71F,.60F);
}
#endregion
#region Fields
float kDotDiameter= 7.0f;
float kDotSpacer = 7.0f;
int _currentPage;
int _numberOfPages;
CGColor CurrenColor{get;set;}
CGColor OtherColor{get;set;}
public int currentPage
{
set
{
_currentPage = Math.Min(Math.Max(0, value),_numberOfPages-1);
this.SetNeedsDisplay();
}
get{return _currentPage;}
}
public int numberOfPages
{
set
{
_numberOfPages = Math.Max(0,value);
_currentPage = Math.Min(Math.Max(0, _currentPage), _numberOfPages-1);
this.SetNeedsDisplay();
}
get{return _numberOfPages;}
}
#endregion
#region Overrides
public override void Draw (RectangleF rect)
{
base.Draw (rect);
CGContext context = UIGraphics.GetCurrentContext();
context.SetAllowsAntialiasing(true);
RectangleF currentBounds = this.Bounds;
float dotsWidth = this.numberOfPages*kDotDiameter + Math.Max(0,this.numberOfPages-1)*kDotSpacer;
float x = currentBounds.GetMidX() - dotsWidth/2;
float y = currentBounds.GetMidY() - kDotDiameter/2;
for (int i = 0; i < _numberOfPages; i++) {
RectangleF circleRect = new RectangleF(x,y,kDotDiameter,kDotDiameter);
if (i==_currentPage) {
context.SetFillColor(this.CurrenColor);
}
else {
context.SetFillColor(this.OtherColor);
}
context.FillEllipseInRect(circleRect);
x += kDotDiameter + kDotSpacer;
}
}
public override void TouchesBegan (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
PointF touchpoint = (touches.AnyObject as MonoTouch.UIKit.UITouch).LocationInView(this);
RectangleF currentbounds = this.Bounds;
float x = touchpoint.X- currentbounds.GetMidX();
if (x<0 && this.currentPage>=0) {
this.currentPage--;
Change(this,EventArgs.Empty);
}
else if (x>0 && this.currentPage<this.numberOfPages-1) {
this.currentPage++;
Change(this,EventArgs.Empty);
}
}
#endregion
#region delegate
public event EventHandler Change;
#endregion
}

Resources