Mouse Cursor on LCD

Any ideas on how to show a mouse cursor on Glide running on G120 if I want to navigate with a USB Mouse.

The g120 chip has hardware support to overlay a pointer on the LCD. Not sure if anyone has hooked into it yet.

Any ideas on how to do this

There are a few registers that you need to set with the x,y location of the cursor and a pointer to the cursor image. It’s probably possible without RLP. There are probably some details about how the image is packed and how transparency is stored, but I doubt it’s that difficult. As Andre says you need the LPC1788 user manual from NXP for the details.

I haven’t used glide yet so there is probably a way to do it in glide, but the hardware supported method will be much faster.

If you do get it working then please could you share your code?

I just browsed the Glide code, I assume the DisplayObject class is the key to solve the problem. I am working on something similar, which is not bound to Glide, but I want to solve this problem as well.

I think that we could create a Mouse class that derives from DisplayObject which offers a Invalidate and Render method, that would allow us to re-paint the mouse pointer and make it a first-class citizen of Glade:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) GHI Electronics, LLC.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using System.Threading;
using Microsoft.SPOT;
using GHI.Glide.Geom;

namespace GHI.Glide.Display
{
    /// <summary>
    /// The DisplayObject is the base class for all objects.
    /// </summary>
    public class DisplayObject
    {
        private int _width = 0;
        private int _height = 0;
        private Rectangle _rect = new Rectangle();

        /// <summary>
        /// Indicates the instance name of the DisplayObject.
        /// </summary>
        public string Name;

        /// <summary>
        /// Indicates the alpha transparency value of the object specified.
        /// </summary>
        /// <remarks>Valid values are 0 (fully transparent) and 255 (fully opaque). Default value is 255.</remarks>
        public ushort Alpha = 255;

        /// <summary>
        /// Indicates whether or not the DisplayObject is visible.
        /// </summary>
        /// <remarks>Invisible objects are not drawn nor do they receive touch events.</remarks>
        public bool Visible = true;

        /// <summary>
        /// Indicates whether or not the DisplayObject is enabled.
        /// </summary>
        /// <remarks>Disabled objects do not receive touch events.</remarks>
        public bool Enabled = true;

        /// <summary>
        /// Indicates whether or not the DisplayObject is interactive.
        /// </summary>
        /// <remarks>Non-interactive objects do not receive touch events. This allows disabled objects to keep their state.</remarks>
        public bool Interactive = true;

        /// <summary>
        /// Object that contains data about the display object.
        /// </summary>
        public object Tag = null;

        /// <summary>
        /// Indicates the DisplayObjectContainer object that contains this display object.
        /// </summary>
        public DisplayObjectContainer Parent;

        /// <summary>
        /// Tap event.
        /// </summary>
        public event OnTap TapEvent;

        /// <summary>
        /// Triggers a tap event.
        /// </summary>
        /// <param name="sender">Object associated with the event.</param>
        public void TriggerTapEvent(object sender)
        {
            if (TapEvent != null)
                TapEvent(sender);
        }

        /// <summary>
        /// Is TapEvent null?
        /// </summary>
        /// <returns>True if TapEvent is null; false otherwise.</returns>
        public bool TapEventIsNull()
        {
            return (TapEvent == null);
        }

        /// <summary>
        /// Gesture event.
        /// </summary>
        public event OnGesture GestureEvent;

        /// <summary>
        /// Triggers a gesture event.
        /// </summary>
        /// <param name="sender">Object associated with the event.</param>
        /// <param name="args">Touch gesture event arguments.</param>
        public void TriggerGestureEvent(object sender, TouchGestureEventArgs args)
        {
            if (GestureEvent != null)
                GestureEvent(sender, args);
        }

        /// <summary>
        /// Renders this display object.
        /// </summary>
        public virtual void Render()
        {
            // Do something
        }

        /// <summary>
        /// Renders this display object on a specified bitmap.
        /// </summary>
        /// <param name="bitmap"></param>
        public virtual void Render(Bitmap bitmap)
        {
            // Do something
        }

        /// <summary>
        /// Renders this display object and flushes it to the screen.
        /// </summary>
        public virtual void Invalidate()
        {
            Render();
            Glide.Flush(this);
        }

        /// <summary>
        /// Handles touch down events.
        /// </summary>
        /// <param name="e">Touch event arguments.</param>
        /// <returns>Touch event arguments.</returns>
        public virtual TouchEventArgs OnTouchDown(TouchEventArgs e)
        {
            return e;
        }

        /// <summary>
        /// Handles touch up events.
        /// </summary>
        /// <param name="e">Touch event arguments.</param>
        /// <returns>Touch event arguments.</returns>
        public virtual TouchEventArgs OnTouchUp(TouchEventArgs e)
        {
            return e;
        }

        /// <summary>
        /// Handles touch move events.
        /// </summary>
        /// <param name="e">Touch event arguments.</param>
        /// <returns>Touch event arguments.</returns>
        public virtual TouchEventArgs OnTouchMove(TouchEventArgs e)
        {
            return e;
        }

        /// <summary>
        /// Handles touch gesture events.
        /// </summary>
        /// <param name="e">Touch event arguments.</param>
        /// <returns>Touch event arguments.</returns>
        public virtual TouchGestureEventArgs OnTouchGesture(TouchGestureEventArgs e)
        {
            return e;
        }

        /// <summary>
        /// Disposes all disposable objects in this display object.
        /// </summary>
        public virtual void Dispose()
        {
            // Do something
        }

        /// <summary>
        /// Indicates the x coordinate of the DisplayObject instance relative to the local coordinates of the parent DisplayObjectContainer.
        /// </summary>
        public int X;

        /// <summary>
        /// Indicates the y coordinate of the DisplayObject instance relative to the local coordinates of the parent DisplayObjectContainer.
        /// </summary>
        public int Y;

        /// <summary>
        /// Indicates the width of the display object, in pixels.
        /// </summary>
        public virtual int Width
        {
            get { return _width; }
            set
            {
                _width = value;
                _rect.Width = value;
            }
        }

        /// <summary>
        /// Indicates the height of the display object, in pixels.
        /// </summary>
        public virtual int Height
        {
            get { return _height; }
            set
            {
                _height = value;
                _rect.Height = value;
            }
        }

        /// <summary>
        /// Indicates the rectangle bounds of this display object.
        /// </summary>
        public Rectangle Rect
        {
            get
            {
                _rect.X = X;
                if (Parent != null)
                    _rect.X += Parent.X;

                _rect.Y = Y;
                if (Parent != null)
                    _rect.Y += Parent.Y;

                return _rect;
            }
        }

    }
}


Regarding the “MouseClick” event, we could try to fire the touch_down event when the mouse is clicked or implement a complete new event and extend the class for our needs. I am not sure (because not tested, no time today), but pretty convinced that we could solve the problem using this class.

From what I can tell the hardware register is fairly simple to use and shouldn’t need RLP as it’s all done using dedicated registers.

[quote]11.4.2 Hardware cursor support
The hardware cursor feature reduces software overhead associated with maintaining a
cursor image in the LCD frame buffer.
Without this feature, software needed to:
• Save an image of the area under the next cursor position.
• Update the area with the cursor image.
• Repair the last cursor position with a previously saved image.
In addition, the LCD driver had to check whether the graphics operation had overwritten
the cursor, and correct it. With a cursor size of 64x64 and 24-bit color, each cursor move
involved reading and writing approximately 75 kB of data.
The hardware cursor removes the requirement for this management by providing a
completely separate image buffer for the cursor, and superimposing the cursor image on
the LCD output stream at the current cursor (X,Y) coordinate.
To move the hardware cursor, the software driver supplies a new cursor coordinate. The
frame buffer requires no modification. This significantly reduces software overhead.
The cursor image is held in the LCD controller in an internal 256x32-bit buffer memory.[/quote]

So you can either have one 64x64 cursor or select between one of 4 32x32 cursors. Note this is still just one cursor, but you can rapidly switch between different images e.g. cursor up and cursor down. You can’t have 4 independent cursors unfortunately.

[quote]Cursor pixel encoding
Each pixel of the cursor requires two bits of information. These are interpreted as Color0,
Color1, Transparent, and Transparent inverted.
In the coding scheme, bit 1 selects between color and transparent (AND mask) and bit 0
selects variant (XOR mask).
Table 217 shows the pixel encoding bit assignments.
[/quote]

So it’s basically only 2 colours + transparent. Transparent invert means that the pixel will be visible regardless of the underlying colour.

1 Like

You might find Clix/Tinkr has something that can help you on it’s way if you choose not to use something hardware based. [ Thanks Thom / @ Skewworks for throwing that code open and @ Reinhard for taking it on ]

https://www.ghielectronics.com/community/forum/topic?id=14992 and GitHub - osre77/Tinkr: Tinkr provides a comprehensive set of GUI controls that allow you to quickly develop graphic applications for NETMF devices with natively supported screens as well as support for the new Skewworks Image32 and multiple application standards! The initial code of Tinkr v2.5.0 was donated by Skewworks (www.Skewworks.com).

1 Like

@ hagster

That sounds pretty good and would make everything more powerful (less resources, more speed). What I don’t understand is, how will this hardware-cursor connect to the UI, e.g. Glade. Would that replace the touch-device?

@ Brett Thanks for the hint :slight_smile: I read about the UI created by @ Skeworks and that @ Reinhard offered to maintain the repos. Will check that as well.

It just handles the resource intensive graphical overlay. You still need to keep track of the XY location and event handling in your code.

1 Like

Wow…This is good…have to dig through all the code to get grasp of it.

It would also be useful to overlay text over a picture.
I do a bit of animation on the opening screen by moving an icon on top of a picture.
since it take a lot of mips it slow the startup a bit.
This should help with that

and games people want to write

@ Brett Thanks for the explanation :slight_smile: Totally new to that and willed to learn more, fast.

@ hagster Is that the right piece of documentation?

http://www.nxp.com/documents/user_manual/UM10237.pdf

@ AWSOMEDEVSIGNER - I do not have a G120, but if I am not mistaken it has a LPC1788, the manual you referenced is for the LPC24xx series processors.

http://www.nxp.com/documents/user_manual/UM10470.pdf

Update: scanning the earlier posts, @ hagster mentioned that it is indeed a LPC1788, so the link I provided should be what you want.

1 Like

@ taylorza Thanks for the hint and for the link :slight_smile: I am a starter. So I need all the help I can get.

Update:
And if I assume right, the LPC2478 documentation would then be right for my Fez Spider board which is based on the EMX Module (SoM).

@ AWSOMEDEVSIGNER - Correct, I have a spider and confirmed the chip number. GHI for some reason does not like listing the specifics of the components in the specifications of their boards, at least not consistently from what I can see.

1 Like

@ taylorza

Thanks for the feedback :slight_smile: I have downloaded all the required documents now and I am going to setup a separate machine (have some laptop with a broken display, a prototype) only for netmf development. Don’t want to mix all this platforms on one machine.

@ AWSOMEDEVSIGNER - Well, let me give you fair warning, if you are only just getting into this beware it is addictive! I started back in 2012 and every time I tackle something it is a new learning experience, the perpetual beginner… Good luck and have fun.

@ taylorza

LOL, yeah. I am already addicted. Lot’s of fun and a great community! Thank you :slight_smile:

1 Like

It starts on page 294 and looks almost identical to the g120 chip doc. It’s probably only a matter of changing the register addresses to make it portable between them.

1 Like