GTK3+ How to handle touchpad zoom gesture? - gtk

I want to get TOUCHPAD pinch zoom gesture from GTK. (I'm using Gnome 3.38 on Wayland, and gestures work well)
GTK Version: 3.24.29
I have this Vala code but it isn't worked:
using Gtk;
using Gdk;
namespace Slidertest {
[GtkTemplate (ui = "/com/eminfedar/slidertest/window.ui")]
public class Window : Gtk.ApplicationWindow {
[GtkChild]
EventBox eventbox;
public Window (Gtk.Application app) {
Object (application: app);
print("GTK: %d.%d.%d\n", Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSION);
eventbox.add_events(EventMask.TOUCHPAD_GESTURE_MASK);
var zoom = new GestureZoom(eventbox);
zoom.set_propagation_phase(PropagationPhase.BUBBLE);
print("recog: %d\n", (int)zoom.is_recognized());
zoom.scale_changed.connect((scale) => {
print("Scale:%f\n", scale);
});
zoom.begin.connect((seq) => {
print("BEGIN\n");
});
zoom.end.connect((seq) => {
print("END\n");
});
}
}
}
zoom.is_recognized() always returns 0. How can I make it work?
Thanks!

Related

Simulated TouchEventData does not work on Scrollbar

I am currently trying to write my own multitouch handler in Unity. I am using the Enhanced Touch input system to capture touch events, along with simulating touch with mouse. I have successfully gotten native buttons to work with my simulated touch events, however I'm running into an issue with scrollbars.
When touching a scroll bar handle, the handle instantly shoots to the end of the scroll bar. Here is how I am generating the PointerEventData:
using ETouch = UnityEngine.InputSystem.EnhancedTouch.Touch;
protected Func<ETouch, PointerEventData> pointer => GetPointer;
protected PointerEventData GetPointer(ETouch touch)
{
return new PointerEventData(EventSystem.current)
{
position = touch.screenPosition,
scrollDelta = touch.screenPosition - touch.startScreenPosition,
};
}
And here is how I'm dispatching the event data to the Scrollbar:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using ETouch = UnityEngine.InputSystem.EnhancedTouch.Touch;
public class EScrollbarEventHandler : ETouchEventHandler
{
public Scrollbar scroll;
bool moving = false;
protected override void StartTouch(ETouch touch)
{
//Debug.Log(pointer(touch).scrollDelta);
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.pointerEnterHandler);
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.pointerDownHandler);
}
protected override void StationaryTouch(ETouch touch)
{
if (moving)
{
moving = false;
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.endDragHandler);
}
}
protected override void MoveTouch(ETouch touch)
{
if (!moving)
{
moving = true;
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.beginDragHandler);
}
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.pointerMoveHandler);
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.dragHandler);
}
protected override void EndTouch(ETouch touch)
{
if (moving)
{
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.endDragHandler);
}
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.pointerUpHandler);
ExecuteEvents.Execute(scroll.gameObject, pointer(touch), ExecuteEvents.pointerExitHandler);
base.EndTouch(touch);
}
}
Currently, the scrollbar's Enter, Down, Up, and Exit event handlers are working. The scrollbar changes color when touched, however the scrollbar's handle immediately moves to the end of the scrollbar. This happens on both vertical and horizontal scrollbars. I'm not sure if there are any other properties that need to be set in the PointerEventData. Any help would be appreciated, thanks.
Edit:
After looking through the Scrollbar and other components, it appears that any native UI component that depends on dragging cannot be modified to operate with the new Enahnced Touch. The reason for this is the components are hard-coded to operate strictly on mouse events. Seeing as I cannot modify the built in components, my only solution is to create my own version of each draggable component.

MAUI GraphicsView mouse click event

I'm new to .Net Maui. Trying to draw my own shapes using GraphicsView and IDrawable. I would like to have the shapes clickable.
Is there a way how to achieve that? Maybe there is another interface something like IClickable I'm not aware of. Or I should use different approach thanGraphicsView.
Thanks :-)
I was able to get this to work using the TapGestureRecognizer and a class that implements ICommand.
In this example I have the GraphicsView as a member called _view in the same class that implements both IDrawable and ICommand, but your design could be different and it should still work.
public class Block : IDrawable, ICommand
{
protected GraphicsView _view = new GraphicsView();
public Block()
{
_view.Drawable = this;
_view.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = this
});
}
void ICommand.Execute(object cmdObject)
{
// Handle the Clicked event here
}
bool ICommand.CanExecute(object cmdObject)
{
return true;
}
event EventHandler ICommand.CanExecuteChanged
{
add { }
remove { }
}
public void Draw(ICanvas canvas, RectF dirtyRect)
{
// Draw on canvas here
}
}

Unity says that 'Button' is not a Component and doesn't derive from Monobehavior

This was originally coded in unity 2018 then ported to unity 2019 because my main project is on that version. It works perfectly in unity 2018 (aside from that button.clicked += used to be button.AddListener())
The only relevant bit of the code is lines 12 - 17 but who knows.
Script is attached to object with the Button component.
Unity 2019.4.11f1
Returns the following error with the setup listed above:
ArgumentException: GetComponent requires that the requested component 'Button' derives from MonoBehaviour or Component or is an interface.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;
using UnityEngine.Events;
public class ButtonProperties : MonoBehaviour {
public ButtonType buttonType;
public string dest;
Button button;
void Start()
{
button = GetComponent<Button>();
//perform different functions dependant on the button type
if (buttonType == ButtonType.Scene)
{
//add ButtonLoadScene as a listener to the the button
button.clicked += ButtonLoadScene;
}
else if (buttonType == ButtonType.Menu)
{
button.clicked += ButtonLoadMenu;
}
//change button text to "Load Scene" + the name of the scene
string str = "Load " + dest;
GetComponentInChildren<TextElement>().text = str;
}
//private scene loader because event listeners cant take arguments >:(
void ButtonLoadScene()
{
SceneManager.LoadScene(dest);
}
void ButtonLoadMenu()
{
//array of all canvases in the scene
Canvas[] canvases = GameObject.FindObjectsOfType<Canvas>();
//foreach canvas
foreach (Canvas canvas in canvases)
{
//if the canvases name is the desired name
if (canvas.name == dest)
{
//turn all canvases off
foreach (Canvas c in canvases)
{
c.enabled = false;
}
//turn current canvas on
canvas.enabled = true;
//break loop
break;
}
}
}
}
public enum ButtonType
{
Scene,
Menu
};
I also tested this by adding a NewBehaviourScript to the button with Button button; and, in the start function, Start() {button = GetComponent<Button>();}
Same error
I believe you are using the wrong namespace for your button. Try changing:
using UnityEngine.UIElements;
to
using UnityEngine.UI;
There is a Button in both namespaces, but the one in UnityEngine.UI is likely the component you're working with.
Had somebody else on the team test the build, as I started to think from the comment thread, I was missing the UI library. Changing it to the UI library was the solution but not for me until I restarted the computer. Thank you Thomas Finch for the help.

Accessing Color Frames with Unity and Tango 'Leibniz'

I'm just starting to tinker with Tango and Unity. Unfortunately there doesn't seem to be any documentation or examples on how to access color data in Unity with the latest release.
I've been using the motion tracking example from GitHub (https://github.com/googlesamples/tango-examples-unity) as a starting point, trying to read incoming color frames the same way pose and depth data are read. I'm assuming the best way is to go through the "ITangoVideoOverlay" interface and "OnTangoImageAvailableEventHandler" callback.
All I am trying to do right now is to get the "OnTangoImageAvailableEventHandler" callback working and I can't quite figure it out. I have "Enable Video Overlay" checked on the Tango Manager and the following script connected to a GUI Text object for debugging.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using Tango;
using System;
public class VideoController : MonoBehaviour, ITangoVideoOverlay
{
private TangoApplication m_tangoApplication;
private bool debugB = false;
public Text debugText;
// Use this for initialization
void Start () {
m_tangoApplication = FindObjectOfType<TangoApplication>();
m_tangoApplication.Register(this);
}
// Update is called once per frame
void Update () {
if (debugB)
debugText.text = "TRUE";
else
debugText.text = "FALSE";
}
// No Unity API
public void OnTangoImageAvailableEventHandler(Tango.TangoEnums.TangoCameraId id, Tango.TangoUnityImageData image)
{
debugB = true;
}
}
Is there some initialization of the camera that I am missing? Or is the preferred method still to use the VideoOverlayListener like in this older code: Getting color data in Unity
I know it's also possible to directly access the camera through Unity (disabling depth). But I would like to learn the "proper way" first.
Thank you for your time!
Update 04/28/15 - Latest version of the script, callback works! Still needs a conversion to RGB color
This script was written as an addition to Google's Tango Motion Tracking example on GitHub. Attach the script to a Unity camera and then link the public field "m_viewScreen" to a mesh object (like a plane) for the video texture to display on.
using System.Collections;
using UnityEngine;
using Tango;
using System;
public class VideoController : MonoBehaviour
{
private TangoApplication m_tangoApplication;
private Texture2D m_texture;
private Material m_screenMaterial;
private MeshFilter m_meshFilter;
private bool m_readyToDraw = false;
// Link to a mesh object for displaying texture
public GameObject m_viewScreen;
// Use this for initialization
void Start ()
{
// Tango initilization
m_tangoApplication = FindObjectOfType<TangoApplication>();
m_tangoApplication.Register(this);
m_tangoApplication.RegisterPermissionsCallback(_OnTangoApplicationPermissionsEvent);
// Initialize view object Material
m_meshFilter = m_viewScreen.GetComponent<MeshFilter> ();
m_screenMaterial = new Material(Shader.Find("Mobile/Unlit (Supports Lightmap)"));
// Begin to texture to webcam
m_texture = m_tangoApplication.GetVideoOverlayTexture();
m_texture.Apply();
if (m_screenMaterial != null)
{
// Apply the texture
m_screenMaterial.mainTexture = m_texture;
m_meshFilter.GetComponent<MeshRenderer>().material = m_screenMaterial;
// Connect the texture to the camera
if (m_tangoApplication.m_useExperimentalVideoOverlay)
{
VideoOverlayProvider.ExperimentalConnectTexture(TangoEnums.TangoCameraId.TANGO_CAMERA_COLOR, m_texture.GetNativeTextureID(), _OnUnityFrameAvailable);
}
else
{
VideoOverlayProvider.ConnectTexture(TangoEnums.TangoCameraId.TANGO_CAMERA_COLOR, m_texture.GetNativeTextureID());
}
}
}
private void _OnTangoApplicationPermissionsEvent(bool permissionsGranted)
{
m_readyToDraw = true;
}
private void _OnUnityFrameAvailable(System.IntPtr callbackContext, Tango.TangoEnums.TangoCameraId cameraId)
{
// Do fun stuff here!
}
void OnPreRender()
{
if (m_readyToDraw)
{
VideoOverlayProvider.RenderLatestFrame(TangoEnums.TangoCameraId.TANGO_CAMERA_COLOR);
GL.InvalidateState();
}
}
void Update ()
{
// Do other fun stuff here!
}
}
From what I could find, they changed the whole system so it's easier to access the image, where all the image grabbing is handle by the Tango object.
In your Start after grabbing the Tango App, try this:
m_texture = m_tangoApplication.GetVideoOverlayTexture();
m_texture.Apply();
if (m_screenMaterial != null)
{
// Apply the texture
m_screenMaterial.mainTexture = m_texture;
m_meshFilter.GetComponent<MeshRenderer>().material = m_screenMaterial;
// Connect the texture to the camera
if (m_tangoApplication.m_useExperimentalVideoOverlay)
{
VideoOverlayProvider.ExperimentalConnectTexture(TangoEnums.TangoCameraId.TANGO_CAMERA_COLOR, m_texture.GetNativeTextureID(), _OnUnityFrameAvailable);
}
else
{
VideoOverlayProvider.ConnectTexture(TangoEnums.TangoCameraId.TANGO_CAMERA_COLOR, m_texture.GetNativeTextureID());
}
}
and you'll need this somewhere else for the callback event:
private void _OnUnityFrameAvailable(System.IntPtr callbackContext, Tango.TangoEnums.TangoCameraId cameraId)
{
// Do fun stuff here!
}
But it doesn't really need to do anything. Of course, the image is still in YUV-NV12 format so you'll need to convert it to RGB (or wait til their next release which should fix it).
Edit: Oops! Forgot you need one more call to actually update the texture on the AR material:
In Start() after grabbing the TangoApp:
m_tangoApplication.RegisterPermissionsCallback(_OnTangoApplicationPermissionsEvent);
Then:
private void _OnTangoApplicationPermissionsEvent(bool permissionsGranted)
{
m_readyToDraw = true;
}
void OnPreRender()
{
if (m_readyToDraw)
{
VideoOverlayProvider.RenderLatestFrame(TangoEnums.TangoCameraId.TANGO_CAMERA_COLOR);
GL.InvalidateState();
}
}
Hope that works now!

How do I get a GWT menu popup to stay within the browser window?

My GWT app uses a DockLayoutPanel for primary layout and the page itself does not scroll. I have a PopupPanel with a MenuBar and sometimes when a MenuItem is selected the sub menu bar goes off the bottom of the screen abruptly forcing a new scroll bar into the browser and messing up the layout.
How do I get the menu popup to behave nicely and reposition itself upward when the default positioning would put it out of the browser viewport (the way that PopupPanel.showRelativeTo(uiTarget) positioning works)?
In looking at the MenuBar source, it looks like all the layout is done in private methods, so I can't fix it in subclass, and I don't see any events I can listen to that would allow me to do the repositioning myself.
Take a look at http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/6185225fec64c091/4954d91d1461c71f?lnk=gst&q=context+menu#4954d91d1461c71f.
We've been using this strategy quite successfully for a while now.
Update: There is a bit more to be done. Specifically:
Create a reposition() method, which:
Determines the max width of all the menu items
Checks the left edge of the menu + the max width; if greater than the Window's width, use "DOM.setStyleAttribute(elem, "left", left + "px");" to move the menu
Get the height of the menu; if top of the menu + height of the menu > Window's height, use "DOM.setStyleAttribute(elem, "top", top + "px");" to move it up.
In the onAttach() method, use a deferred command to invoke the reposition() method.
You can intercept the popup just before it is shown, but after its size has been created. This way you have the width of the popup and could move it to another position:
#Override
public void onContextMenu(ContextMenuEvent evt) {
int x = evt.getNativeEvent().getClientX();
int y = evt.getNativeEvent().getClientY();
popupMenu.setPopupPositionAndShow(new PositionCallback() {
#Override
public void setPosition(int offsetWidth, int offsetHeight) {
if (x + offsetWidth > Window.getClientWidth()) {
x = Window.getClientWidth() - offsetWidth;
}
//use same technique for height if you want for y, then
setPosition(x, y);
}
});
}
(I know this is an old question, but still comes up if you search for this, so I thought of providing present solution)
Emm...
It is an interesting question...
Looking at the MenuBar source code... especially the method openPopup
private void openPopup(final MenuItem item) {
// Only the last popup to be opened should preview all event
if (parentMenu != null && parentMenu.popup != null) {
parentMenu.popup.setPreviewingAllNativeEvents(false);
}
// Create a new popup for this item, and position it next to
// the item (below if this is a horizontal menu bar, to the
// right if it's a vertical bar).
popup = new DecoratedPopupPanel(true, false, "menuPopup") {
{
setWidget(item.getSubMenu());
setPreviewingAllNativeEvents(true);
item.getSubMenu().onShow();
}
#Override
protected void onPreviewNativeEvent(NativePreviewEvent event) {
// Hook the popup panel's event preview. We use this to keep it from
// auto-hiding when the parent menu is clicked.
if (!event.isCanceled()) {
switch (event.getTypeInt()) {
case Event.ONMOUSEDOWN:
// If the event target is part of the parent menu, suppress the
// event altogether.
EventTarget target = event.getNativeEvent().getEventTarget();
Element parentMenuElement = item.getParentMenu().getElement();
if (parentMenuElement.isOrHasChild(Element.as(target))) {
event.cancel();
return;
}
super.onPreviewNativeEvent(event);
if (event.isCanceled()) {
selectItem(null);
}
return;
}
}
super.onPreviewNativeEvent(event);
}
};
popup.setAnimationType(AnimationType.ONE_WAY_CORNER);
popup.setAnimationEnabled(isAnimationEnabled);
popup.setStyleName(STYLENAME_DEFAULT + "Popup");
String primaryStyleName = getStylePrimaryName();
if (!STYLENAME_DEFAULT.equals(primaryStyleName)) {
popup.addStyleName(primaryStyleName + "Popup");
}
popup.addPopupListener(this);
shownChildMenu = item.getSubMenu();
item.getSubMenu().parentMenu = this;
// Show the popup, ensuring that the menubar's event preview remains on top
// of the popup's.
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
// depending on the bidi direction position a menu on the left or right
// of its base item
if (LocaleInfo.getCurrentLocale().isRTL()) {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft() - offsetWidth
+ 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft()
+ item.getOffsetWidth() - offsetWidth,
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
} else {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft()
+ MenuBar.this.getOffsetWidth() - 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft(),
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
}
}
});
}
It is interesting to point the snippet as
...
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
// depending on the bidi direction position a menu on the left or right
// of its base item
if (LocaleInfo.getCurrentLocale().isRTL()) {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft() - offsetWidth
+ 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft()
+ item.getOffsetWidth() - offsetWidth,
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
} else {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft()
+ MenuBar.this.getOffsetWidth() - 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft(),
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
}
}
});
...
... so I may suppose there is a sense to play around MenuItem object especially its UIObject inherited methods like getAbsoluteLeft() and getAbsoluteTop(), of course ...
I would recommend to extend MenuItem something in this way
//not tested
public class MyMenuItem extends MenuItem
{
private MenuBar aSubMenuBar;//ItemMenu's submenu
//...
#Override
public int getAbsoluteTop() {
// TODO Auto-generated method stub
return super.getAbsoluteTop()+movePopupTo();
}
private int movePopupTo()
{
int moveTo=0;
int bottom=RootPanel.getBodyElement().getAbsoluteBottom();
int rest=bottom -(super.getAbsoluteTop()+this.getaSubMenuBar().getOffsetHeight());
if(rest<0)
{
moveTo=rest;
}
return moveTo;
}
public MenuBar getaSubMenuBar() {
return aSubMenuBar;
}
public void setaSubMenuBar(MenuBar aSubMenuBar) {
this.aSubMenuBar = aSubMenuBar;
}
//...
}
It is not the final solution but a basic conception.
Report if that helped
Good luck