Haxe: Handling horizontal scroll events - input

I recently started using Haxe, so pardon me if my question has an obvious answer or if my description of the problem is a little sloppy, but I'm going to try my best to explain it.
I'm working on a laptop that has a multitouch-supported track pad, and a normal optical mouse with only a vertical scroll wheel (no horizontal clicking available on there). I'm looking for a way to handle horizontal scroll input / events. OpenFL's mouse events support vertical scrolling well enough. Both the mouse scrolling and the two-finger track pad scrolling work fine for the vertical axis. It looks like the same event is generated when either of those input methods are used, which is understandable. But I can't seem to find an event that would be generated when a horizontal scroll is performed. The track pad allows for horizontal scrolling, since web browsers respond to the command, but I can't find any way to make my program respond to this input. Lime's "onMouseWheel" function doesn't respond to the input either. Do you guys have any suggestions for capturing this kind of input for an app targeted for Windows?
Thanks in advance
UPDATE: What I'm looking for here is not a question of how to scroll the screen horizontally, but how to recognize the horizontal scroll event coming from hardware, for example two fingers on the track pad or a sideways click of the middle mouse wheel. Lime's onMouseWheel has two params, deltaX and deltaY, but no events are triggered that give back a non-zero deltaX value. Vertical scrolling fires an event that returns deltaX = 0 and deltaY = +/- 1, but horizontal scrolling doesn't even trigger an event.

This can be done in several ways. The first is to add an event handler to mouse wheel for the object instance that you want to attach the event handler to, so MouseEvent.MOUSE_WHEEL and use the delta variable to determine the scroll direction. What you may also need to do is handle a key down event which enables horizontal scrolling instead of vertical.
Some example code:
mySprite.addEventHandler(MouseEvent.MOUSE_WHEEL, onScroll);
mySprite.addEventHandler(KeyboardEvent.KEY_DOWN, onKeyDown);
mySprite.addEventHandler(KeyboardEvent.KEY_UP, onKeyUp);
...
private var horizontal:Bool;
private function onScroll(e:MouseEvent):Void
{
if (e.delta > 0 && horizontal)
mySprite.scrollRect.x++;
else if (e.delta < 0 && horizontal)
mySprite.scrollRect.x--;
}
private function onKeyDown(e:KeyboardEvent):Void
{
if (e.keyCode == 18)
horizontal = true;
}
private function onKeyUp(e:KeyboardEvent):Void
{
if (e.keyCode == 18)
horizontal = false;
}
You will need to define the scrollRect in your constructor somewhere to specify the scrolling bounds of the sprite.

Related

Custom context menu XAML for WP8

I try to implement a custom ContextMenu in a LongListSelector.
I'm not using the ContextMenu from Microsoft.Phone.Controls.Toolkit, it's basically the same as in the Rowi App:
(source: hiddenpineapple.com)
Approach 1
My list item toggles a VisualState on hold and an overlay is shown with controls in it.
The problem
I can't find a way to go back to the default state when the user clicks outside of the list item (as in the default ContextMenu).
Approach 2
I've implemented a custom template for the toolkit ContextMenu which looks exactly the same. I had to move its margin top to -itemHeight, as by default it is below the item.
The problem
The problem with this solution is, that it automatically closes itself when opening and I couldn't figure out how to avoid this.
Another problem was that it didn't work well with TiltEffect.IsTiltEnabled from the Toolkit (visual problems).
I need your help
Any suggestions on how to get this working?
Answer
Thanks to Cheese, now I know how to properly close the menu when the user clicks outside.
His suggestion was to get the coordinates of a Tap event on the current page, and check if it's inside the menu. When not, close the menu.
So I added a Tap listener to the page when the menu opens, and removed it when the menu closes. From the page listener I got the event coordinates and could check if it's inside the control which holds the menu (same size and position). I received the position of the control with Point leftUpperPoint = control.TransformToVisual(page).Transform(new Point(0, 0)) and the rightLowerPoint by adding the ActualWidth and ActualHeight.
But then I realized:
Why should I even calculate if the tap is inside the menu? I always want to close the menu when the user taps anywhere on the screen. If it's outside, yes. If it's on a menu button, yes.
Another modification I made was to listen for MouseLeftButtonDown instead of Tap as it also triggers when the user swipes.
So I removed this code and came up with the following:
private void ToggleMenu(object sender, System.Windows.Input.GestureEventArgs e)
{
PhoneApplicationFrame frame = ((PhoneApplicationFrame)Application.Current.RootVisual);
VisualState state = this.States.CurrentState;
if (state == null || state.Name == "DefaultState")
{
frame.MouseLeftButtonDown += MouseDownDelegate;
this.State = "MenuState";
}
else
{
frame.MouseLeftButtonDown -= MouseDownDelegate;
this.State = "DefaultState";
}
}
private void MouseDownDelegate(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ToggleMenu(sender, null);
}
This works perfectly!
Thanks to Cheese for the hint.
Something like this by #denniscode http://dotnet.dzone.com/articles/rowi-show-tap-menu
Approach 1 problem
The best solution would be:
Get the menus coordinates, when user makes a tap - you check are tap coordinates on menu or not, if not - dissmiss - simple.
Approach 2 problem
I guess you had some button in a corner and when you tapped on it - nothing happened? And when you dissmissed the Tilt all worked. It seems that tilt works faster than a click, so, tilt changes the button coordinates, and device thiks you have missed/or dragged off
You can use what #ScottIsAFool suggested and maybe create another Dependency Property on your TapMenu control of type UIElement named CloseWhenTappedElement and automatically listen for Tap events inside your control once set. For example
<Grid x:Name="TapArea"/>
<TapMenu CloseWhenTappedElement="{Binding ElementName=TapArea"}/>

ScrollViewer and SetHorizontalOffset

I use scrollviewer in my windows store application, but after calling SetHorizontalOffset function some times scrollviewer doesn't change horizontal scrolling. The same thing with vertical scrolling. Does anybody know how to work with it? May be scrollviewer scroll only for visibility for offset (I mean that if it's see that user can see offset its doesn't scroll at all)
It appears the ScrollViewer's offset lags by one frame.
If the below code is run every frame, diffPrevDesiredActual is always 0. That is to say, the value provided by ChangeView does not take affect immediately.
...
var scrollPosition = /*some new value*/;
MyScrollViewer.ChangeView(null, scrollPosition, null, true);
var current = MyScrollViewer.VerticalOffset;
var diffDesiredActual = scrollPosition - current;
var diffPrevDesiredActual = previous - current;
previous = scrollPosition;
...
private double previous;
If nothing on your screen is animating when you change the scroll offset, then it is possible the ScrollViewer won't show the new value until something triggers the draw of a new frame. To test this hypothesis, try adding an infinite animation (eg ProgressRing) to ensure frames are constantly being drawn.

Sencha Touch: After scrolling a panel using a button tap it back to initial position again when scroll end

I am trying to scroll a panel using button tap, and the panel is scrolling as I want. But my problem is that,
After scroll end it back again to its initial position, doesn't stick to its new position.
Why this behavior and how can I get leave from this?
Code I used (working just fine)
var container = this.getDealdetails();
container.getScrollable().getScroller().scrollTo(x , y, true);
The scrollable container will scroll back if the scroll to position is greater than the height of the container.
This is best demonstrated with an example. Run this fiddle: http://www.senchafiddle.com/#8Qnt8
Make your browser window smaller in height and note how it behaves. Hope this makes sense.
var panel= Ext.getCmp('iObserveCreateRecords');
panel.getScrollable().getScroller().scrollTo(0, 0, true);
//iObserveCreateRecords is panel id

Check if user finished sliding on a continuous UISlider?

In my app, I have a couple of UISlider instances to change various values. The values are displayed right next to the slider, as well as rendered in a 3d space in another visible part of the app.
The 3d part includes some rather heavy calculations, and right now it doesn't seem possible to update it live as the slider changes. That would imply that I'd have to set the slider's continuous property to NO, therefore only getting updates when the slider has finished changing.
I'd prefer to have the displayed value update live, however. Is there a way to have a slider that is continuous (so I can update my value-label in real time) and still sends some kind of message once the user has finished interacting with it? My gut feeling right now is to subclass UISlider and override the touchesEnded: method. Is that feasible?
You can do this with simple target/actions.
Set a target and action for the UIControlEventValueChanged event, and then another target and action for the UIControlEventTouchUpInside event. With the continuous property set to YES, the value changed event will fire as the slider changes value, while the touch up inside event will only fire when the user releases the control.
I just had to do this, so I looked up touch properties, and used the full IBAction header.
This should be a viable alternative for people who want some extra control, though Jas's is definitely easier on the code side.
- (IBAction)itemSlider:(UISlider *)itemSlider withEvent:(UIEvent*)e;
{
UITouch * touch = [e.allTouches anyObject];
if( touch.phase != UITouchPhaseMoved && touch.phase != UITouchPhaseBegan)
{
//The user hasn't ended using the slider yet.
}
}
:D
Also note you should connect the UIControlEventTouchUpOutside event as well in case the user drags his finger out of the control before lifting it.
In Swift 3:
#IBAction func sliderValueChanged(_ slider: UISlider, _ event: UIEvent) {
guard let touch = event.allTouches?.first, touch.phase != .ended else {
// ended
return
}
// not ended yet
}

(C++/CLI) Testing Mouse Position in a Rectangle Relevent to Parent

I've been messing around with the Graphics class to draw some things on a panel. So far to draw, I've just been using the Rectangle Structure. On a panel, by clicking a button, it makes a rectangle in a random place and adds it to an array of other rectangles (They're actually a class called UIElement, which contains a Rectangle member). When this panel is clicked, it runs a test with all the elements to see if the mouse is inside any of them, like this:
void GUIDisplay::checkCollision()
{
Point cursorLoc = Cursor::Position;
for(int a = 0; a < MAX_CONTROLS; a++)
{
if(elementList[a] != nullptr)
{
if(elementList[a]->bounds.Contains(cursorLoc))
{
elementList[a]->Select();
//MessageBox::Show("Click!", "Event");
continue;
}
elementList[a]->Deselect();
}
}
m_pDisplay->Refresh();
}
The problem is, when I click the rectangle, nothing happens.
The UIElement class draws its rectangles in the following bit of code. However, I've modified it a bit, because in this example it uses the DrawReversibleFrame method to do the actually drawing, as I was using Graphics.FillRectangle method. When I changed it, I noticed DrawReversibleFrame drew in a different place than FillRectangle. I believe this is because DrawReversibleFrame draws with its positions relative to the window, while FillRectangle does it relative to whatever Paint event its in (Mines in a panel's Paint method.) So let me just show the code:
void UIElement::render(Graphics^ g)
{
if(selected)
{
Pen^ line = gcnew Pen(Color::Black, 3);
//g->FillRectangle(gcnew SolidBrush(Color::Red), bounds);
ControlPaint::DrawReversibleFrame(bounds, SystemColors::Highlight, FrameStyle::Thick);
g->FillRectangle(gcnew SolidBrush(Color::Black), bounds);
//g->DrawLine(line, bounds.X, bounds.Y, bounds.Size.Width, bounds.Size.Height);
}
else
{
ControlPaint::DrawReversibleFrame(bounds, SystemColors::ControlDarkDark, FrameStyle::Thick);
//g->FillRectangle(gcnew SolidBrush(SystemColors::ControlDarkDark), bounds);
}
}
I add in both DrawReverisbleFrame and FillRectangle so that way I could see the difference. This is what it looked like when I clicked the frame drawn by DrawReversibleFrame:
The orange frame is where I clicked, the black is where its rendering. This shows me that the Rectangle's Contains() method is look for the rectangle relevant to the window, and not the panel. That's what I need fixed :)
I'm wondering if this is happening because the collision is tested outside of the panels Paint method. But I don't see how I could implement this collision testing inside the Paint method.
UPDATE:
Ok, so I just discovered that it appears that what DrawReversibleFrame and FillRectangle draw are always a certain distance apart. I don't quite understand this, but someone else might.
Both Cursor::Position and DrawReversableFrame operate in screen coordinates. That is for the entire screen, everything on your monitor, and not just your window. FillRectangle on the other hand operates on window coordinates, that is the position within your window.
If you take your example where you were drawing with both and the two boxes are always the same distance apart, and move your window on the screen then click again, you will see that the difference between the two boxes changes. It will be the difference between the top left corner of your window and the top left corner of the screen.
This is also why when you check to see what rectangle you clicked isn't hitting anything. You are testing the cursor position in screen coordinates against the rectangle coordinates in window space. It is possible that it would hit one of the rectangles, but it probably won't be the one you actually clicked on.
You have to always know what coordiante systems your variables are in. This is related to the original intention of Hungarian Notation which Joel Spolsky talks about in his entry Making Wrong Code Look Wrong.
Update:
PointToScreen and PointToClient should be used to convert coordinates between screen and window coordinates.