Firemonkey how to implement app drawer-style tab control - firemonkey

I'm going around in circles trying to solve this.
Basically I have a tab control on my Firemonkey android app and can swipe left or right to change tabs and it works fine.
I would like to enhance the swiping so it behaves more like the android app drawer. What I mean by that is if you longtap and slowly slide your finger left or right the screen contents moves left/right with your finger as opposed to what I have now where it only moves a whole screen at a time and not slowly underneath your finger.
A THorzScrollBox is close to the effect I want but it doesn't "snap" onto a single screen but instead can leave your screen half and half on two pages.
Am I making sense here?
I'm using XE8 but I couldn't get it working on earlier versions either!
Many thanks,
Ian.

If someone is interested i just created a new TTabcontrol who enhance the swiping
you can see the code source here
(svn) https://svn.code.sf.net/p/alcinoe/code/
and the demo is here :
(svn) https://svn.code.sf.net/p/alcinoe/code/demos/ALFmxControls
any remark will be welcome :)
i continue also my logic: create a suite of firemonkey control who are very fast to draw, independant of OpenGL and that don't work with the style (i find the style in firemonkey very inefficient and horribly complicated to maintain), so i create this tabcontrol as a descendant of Tcontrol and not as a descendant of TStyleControl.
i think it much (much) more simple to create the title (ie: button) of the tab myself with basic component like trectangle + ttext than updating the so complicated Stylebook for each plateform (ioe, android, windows, macos, etc)
if you compare the unit of my Tabcontrol (ALFmxTabControl.pas) with the unit of the delphi TabControl (Fmx.TabControl.pas) then you will see that i use 3.5x less line of code (1018 vs 3550), and less line of code = always better
please vote for this feature request here :
https://quality.embarcadero.com/browse/RSP-15576

Trying the THorzScrollBox.AniCalculations.SetTargets(...).
eg.
1.Open FMX.HorizontalScroll Sample : CPP\Mobile Snippets\HorizontalScroll
2.Add Form Event : OnResize
3.Write the code :
#include <FMX.InertialMovement.hpp>
void __fastcall THorizontalScrollForm::FormResize(TObject *Sender)
{
TAniCalculations::TTarget target[4];
// Set ths size and position of your slides.
Image1->SetBounds(0, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
Image2->SetBounds(HorzScrollBox1->Width, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
Image3->SetBounds(HorzScrollBox1->Width*2, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
Image4->SetBounds(HorzScrollBox1->Width*3, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
// Assign the check point(your slides' top-left conner).
target[0].TargetType = TAniCalculations::TTargetType::Other;
target[0].Point = TPointD(1, 0);
target[1].TargetType = TAniCalculations::TTargetType::Other;
target[1].Point = TPointD(HorzScrollBox1->Width, 0);
target[2].TargetType = TAniCalculations::TTargetType::Other;
target[2].Point = TPointD(HorzScrollBox1->Width*2, 0);
target[3].TargetType = TAniCalculations::TTargetType::Other;
target[3].Point = TPointD(HorzScrollBox1->Width*3, 0);
HorzScrollBox1->AniCalculations->SetTargets(target, 3);
}

Related

Scroll an element to center

I started using Xamarin UI Test for my Automated tests nearly 9 months ago. Recent updates to the UI of the app I'm working on made it so the elements behind Appbar and Navbar are considered displayed on the screen, which leads to a Tap on the Appbar/Navbar and not the actual element, I asked the devs on my team if there's anything they can do but they couldn't change that weird behaviour from those 2 elements. I've been looking for a way to scroll an element to the center/middle of the view but in vain. Does anyone know how I can accomplish this centred scroll? or a solution for this issue?
Here's the code I usually use :
app.ScrollDownTo(x=>x.Id("Element ID"));
I use Appcenter to run my tests on multiple devices, this is the method I use when I encounter this problem, I can make it work for one device but it probably does not work on other screen sizes :
//I scroll little by little until I find my element
for( int i = 0; app.Query(x=>x.Id("Element ID")).length == 0 && i<10; i++){
//this code performs a very small scroll gesture
app.ScrollDown(x=>x.ClassFull("UIScrollView"));
}
Thanks a lot for your help.

Custom draw ListView Items without border per how TListView itself does it

In a custom control, I custom-draw TListView items myself in the TListView.OnAdvancedCustomDrawItem event. This works well.
I have been experimenting with several Theme classes and parts. For instance, when I use:
HTHEME Theme = OpenThemeData(Handle, L"Explorer::ListView") ;
DrawThemeBackground (Theme, Sender->Canvas->Handle, LVP_LISTITEM, LISS_NORMAL, &ItemRect, NULL);
I get what is to be expected, per Theme explorer (do notice the borders around the item):
But, if I look at a proper VCL TListView object, similar items are painted without a border. I expected this control to use the same Theme class and part. Is that not the case? If so, what class/part should I use to mimic the behavior?
This is what I see (notice the borders in the custom control vs the absence of borders in the true TListView control just below it:
I'm actually getting a 'nicer' result with LVP_GROUPHEADER, but I'm still very curious about LVP_LISTITEM.
FYI, using LVP_GROUPHEADER instead of LVP_LISTITEM. It works well for this type control, so a nice alternative, but I'm still very curious as to why the real ListView control paints no borders using LVP_LISTITEM (I THINK).
Perhaps I should add that I still use old C++ Builder 2009 for this project. This is a low effort attempt to improve the control to give it a life beyond W10 (Especially W11 where current MENU / MENU_POPUPITEM choice is not kind on the eyes). PS. having more problems with TPopupMenu now .. but that's another topic I guess.
A simple code example (not same as in project but showing the border):
#include "uxtheme.h"
#include "Vsstyle.h"
// Project includes uxtheme.lib
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
HTHEME Theme = OpenThemeData(Handle, L"Explorer::ListView") ;
TRect ItemRect = Image1->ClientRect ;
DrawThemeBackground (Theme, Image1->Canvas->Handle, LVP_LISTITEM, LISS_NORMAL, (tagRECT*)&ItemRect, NULL);
CloseThemeData(Theme) ;
}
//---------------------------------------------------------------------------

Unity UI not working properly ONLY on Windows

I have been working on figuring out what is going on with my game's UI for at least two days now, and no progress.
Note that this is a mobile game, but I was asked to build for Windows for visualization and presentation purpose.
So the problem is that when I run my game on the Unity Editor, Android, iOS and Mac platforms the UI works just perfect, but then when I run the game on Windows the UI still works fine UNTIL I load a specific scene.
This specific scene is a loading screen (between main menu and a level) when the level finished async loading, a method called MoveObjects is called in a script in the loading screen, to move some objects that where spawned in the loading screen scene into the level scene (this is not the issue though, since I already try without this method and the problem on the UI persist).
Once the logic of this MoveObjects method is done, a start button is enabled in the loading screen, for the player to click and start playing (I did try moving the start button to the level scene, since maybe it not been a child of the currently active scene could be the issue, but the problem still persist). Is at this point that the UI is partially broken, what I mean with this is, that I can see buttons (and some other UI elements like a scrollbar) changing color/state when the mouse moves over them, but I cannot click on them anymore (the button wont even change to the pressed state).
Also note that I tried creating a development build to see if there was any errors in the console, and I notice that this problem is also affecting the old UI system, so I was not able to interact with the development console anymore.
Also also, note that if I grab and drag the scrollbar before this issue appear, and I keep holding down on the scrollbar until this happens, the mouse gets stuck on the scrollbar, meaning that I cannot interact with the UI anymore, but the scrollbar will still move with the mouse.
I already check that this things are not the source of the problem:
Missing EventSystem, GraphicRaycaster or InputModule.
Another UI element blocking the rest of the UI.
Canvas is Screen Space - Overlay so there is no need for a camera reference.
I only have one EventSystem.
Time.timeScale is 1.
I am not sure what else I could try, so if anyone has any suggestions, I would appreciate it. Thanks.
P.S: I am sorry to say that I cannot share any code or visual material or examples due to the confidentiality.
A major source for a non-working UI for me has always been another (invisible) UI object blocking the raycast (a transparent Image, or a large Text object with raycast on).
Here's a snippet I put together based on info found elsewhere, I often use it to track objects that are masking the raycast in complex UI situations. Place the component on a text object, make sure it's at least few lines tall, as the results will be displayed one under another.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(Text))]
public class DebugShowUnderCursor : MonoBehaviour
{
Text text;
EventSystem eventSystem;
List<RaycastResult> list;
void Start()
{
eventSystem = EventSystem.current;
text = GetComponent<Text>();
text.raycastTarget=false;
}
public List<RaycastResult> RaycastMouse(){
PointerEventData pointerData = new PointerEventData (EventSystem.current) { pointerId = -1, };
pointerData.position = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, results);
return results;
}
void Update()
{
list= RaycastMouse();
string objects="";
foreach ( RaycastResult result in list)
objects+=result.gameObject.name+"\n";
text.text = objects;
}
}

How do I allow the Leap Motion to control my cursor in an OS X application?

So I have a game for Mac OS X built in cocos2D.
I'm using gestures to simulate keyboard commands to control my character and it works really well.
I submitted my game to the AirSpace store and it got rejected on the grounds that the Leap should be used to control my menus as well which is fair enough I guess.
Thing is for the life of me I cannot figure out how this is done. There are no examples out there to show me how to implement it and nothing in the SDK example that makes it clear either.
Does anyone have any examples they'd care to share, I only need it to hijack my cursor and allow a click when held over a button. I really didn't think something so complex would be needed on simply for basic menu navigation.
If this is a Mac only game you should have access to the Quartz event api. This is the easiest way to generate mouse events in OS X...
I would recommend simply tracking the palm (hand) position, and moving the cursor based on that.
This is how I do my palm tracking:
float handX = ([[hand palmPosition] x]);
float handY = (-[[hand palmPosition] y] + 150);
The "+ 150" is the number of millimetres above the Leap device, to use as the '0' location. From there you can move the cursor based on the hand offset from 0.
The function I use to move the cursor (using Quartz):
- (void)mouseEventWithType:(CGEventType)type loc:(CGPoint)loc deltaX:(float)dX deltaY:(float)dY
{
CGEventRef theEvent = CGEventCreateMouseEvent(NULL, type, loc, kCGMouseButtonLeft);
CGEventSetIntegerValueField(theEvent, kCGMouseEventDeltaX, dX);
CGEventSetIntegerValueField(theEvent, kCGMouseEventDeltaY, dY);
CGEventPost(kCGHIDEventTap, theEvent);
CFRelease(theEvent);
}
and an example function call:
[self mouseEventWithType:kCGEventMouseMoved loc:CGPointMake(newLocX, newLocY) deltaX:dX deltaY:dY];
This call will move the mouse. Basically you just pass the new location of the mouse, and the corresponding deltas, relative to the last cursor position.
I can provide more examples such as examples for getting mouse location, clicking the mouse, or even a full mouse moving program...
EDIT 1:
To handle click and drag with Quartz, you can call the same function as above only pass in kCGEventLeftMouseDown.
The catch is that in order to drag you cannot call the kCGEventMouseMoved you must instead pass kCGEventLeftMouseDragged while the drag is happening.
Once the drag is done you must pass a kCGEventLeftMouseUp.
To do a single click (no drag) you simply call mouse down and then up right after, without any drag...

Simulated MouseEvent not working properly OSX

Back in 2010, Pierre asked this question (his accepted answer doesn't work for me).
I'm having the same problem: I am able to successfully move the mouse around (and off!?!) the screen programmatically from my Cocoa Application, however bringing the mouse to the location of my dock doesn't show it (and some other applications aren't registering the mouse moved event, eg. games that remove the mouse)
The method I am using is thus:
void PostMouseEvent(CGMouseButton button, CGEventType type, const CGPoint point)
{
CGEventRef theEvent = CGEventCreateMouseEvent(NULL, type, point, button);
CGEventSetType(theEvent, type);
CGEventPost(kCGSessionEventTap, theEvent);
CFRelease(theEvent);
}
And then when I want to move the mouse I run:
PostMouseEvent(0, kCGEventMouseMoved, mouseLocation);
Note that this code DOES generate mouseover events for things such as links.
Now that's it's 2013, is it possible to fix this issue?
Thanks for your time!
I would both warp the cursor and generate the mouse-move event. I know from experience, for example, that warping the cursor, while it doesn't generate an event itself, modifies the subsequent mouse move event to include the moved distance in its mouse delta. I don't know if your synthesized move event will include the proper delta values on its own.
OK, so evidently MacOSX needs the mouse to be at exactly the edge of the screen for the dock to show!
Because I keep my dock on the left-side of the screen (due to many programs keeping vital buttons at the bottom of their windows), all I had to do was say
if (mouseLocation.x < 0)
{
mouseLocation.x = 0;
}
And it worked!
I am also using KenThomases' idea to warp the cursor as well.
(this answer is marked correct as it allows me to show the dock - however there are still some applications that are not responding to mouse input)

Resources