Wrong peer coordinates when the iPad is rotated


#1

In my iPad application I have components added to the Desktop.

These components look similar to iOS PopOver panels: they are floating panels like balloons with an arrow pointing the component they are referring to.
I decided to add these panels to the desktop in order to break the components hierarchy at a certain point (each UIView is a Juce peer object having its own component tree) for drawing performance reasons.

But a problem popped up: when the iPad is in standard portrait orientation everything goes fine.
When I rotate it, my panels don’t appear on the right position anymore.

From what I can understand, there is a point through coordinates conversions (it seems to me that iOS screen coordinates are always the same regardless of the orientation… and originating on the lower left corner of the display, while Juce manages a rotating origin to accommodate the changes of orientation), where something gets lost.
It seems to me that X and Y directions get swapped somewhere, but I was not able to go any deeper inside that…

Is anyone else having the same problem on iOS?

I suppose you’d be able to see the problem just showing an AlertWindow while the iPad is in landscape orientation.

Also when I drag the AlertWindow around I see that the first touch get caught well, but when I start to drag the alert window around the screen, an offset is introduced between the finger point and the alert window itself.

Thanks for any advise about that,
Alf


#2

i had a similar problem with rotation a while back. something weird was going on with the coordinates. i was seeing negative values for a while.

try setting your app main window to fullscreen (if not already). i think this helps fix it.

– hugh.


#3

For who’s interested here following is how I managed to solve the problem.

I modified three functions: UIViewComponentPeer:getBounds(), UIViewComponentPeer::setBounds() and UIViewComponentPeer::displayRotated().

[code]Rectangle UIViewComponentPeer::getBounds (const bool global) const
{
CGRect r = view.frame;

if (global && view.window != nil)
{
    r = [view convertRect: r toView: view.window];
    r = [view.window convertRect: r toWindow: nil];

    const Rectangle<int> windowBounds (realScreenPosToRotated (convertToRectInt (r)));
    
    return windowBounds;
    
}

return convertToRectInt (r);

}
[/code]

[code]void UIViewComponentPeer::setBounds (int x, int y, int w, int h, const bool isNowFullScreen)
{
fullScreen = isNowFullScreen;
w = jmax (0, w);
h = jmax (0, h);

if (isSharedWindow)
{
    CGRect r = CGRectMake ((CGFloat) x, (CGFloat) y, (CGFloat) w, (CGFloat) h);

    if (view.frame.size.width != r.size.width
         || view.frame.size.height != r.size.height)
        [view setNeedsDisplay];

    view.frame = r;
}
else
{
    const Rectangle<int> bounds (rotatedScreenPosToReal (Rectangle<int> (x, y, w, h)));
    window.frame = convertToCGRect (bounds);

    view.frame = CGRectMake (0, 0, (CGFloat) w, (CGFloat) h);
    handleMovedOrResized();
}

}
[/code]

void UIViewComponentPeer::displayRotated()
{
    Desktop& desktop = Desktop::getInstance();
    const Rectangle<int> oldArea (component->getBounds());
    const Rectangle<int> oldDesktop (desktop.getDisplays().getMainDisplay().userArea);

    const_cast <Desktop::Displays&> (desktop.getDisplays()).refresh();

    if (fullScreen)
    {
        fullScreen = false;
        setFullScreen (true);
    }
    else if (! isSharedWindow)
    {
        Desktop::DisplayOrientation orientation = Desktop::getInstance().getCurrentOrientation();
        
        switch (orientation)
        {
            case Desktop::upright:
                window.transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
                break;
                
            case Desktop::upsideDown:
                window.transform = CGAffineTransformMake(-1, 0, 0, -1, 0, 0);
                break;
                
            case Desktop::rotatedClockwise:
                window.transform = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
                break;
                
            case Desktop::rotatedAntiClockwise:
                window.transform = CGAffineTransformMake(0, 1, -1, 0, 0, 0);
                break;
                
            default:;
        }
        
        view.transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
        
        // this will place the Peer window center at same relative position of the old desktop, but will keep size unchanged
        const float cx = (oldArea.getX() + (oldArea.getWidth() / 2)) / (float) oldDesktop.getWidth();
        const float cy = (oldArea.getY() + (oldArea.getHeight() / 2)) / (float) oldDesktop.getHeight();
        
        const Rectangle<int> newDesktop (desktop.getDisplays().getMainDisplay().userArea);
        
        int x = newDesktop.getWidth() * cx - (oldArea.getWidth()/ 2);
        int y = newDesktop.getHeight() * cy - (oldArea.getHeight() / 2);
        
        setBounds (x, y, oldArea.getWidth(), oldArea.getHeight(), false);
        
//        const float l = oldArea.getX() / (float) oldDesktop.getWidth();
//        const float r = oldArea.getRight() / (float) oldDesktop.getWidth();
//        const float t = oldArea.getY() / (float) oldDesktop.getHeight();
//        const float b = oldArea.getBottom() / (float) oldDesktop.getHeight();
//
//        const Rectangle<int> newDesktop (desktop.getDisplays().getMainDisplay().userArea);
//
//        setBounds ((int) (l * newDesktop.getWidth()),
//                   (int) (t * newDesktop.getHeight()),
//                   (int) ((r - l) * newDesktop.getWidth()),
//                   (int) ((b - t) * newDesktop.getHeight()),
//                   false);
    }
}

Alf


#4

interesting.

i put your changes into my “turn test”. This is the default app created by the introjucer with MainAppWindow() as follows,

MainAppWindow::MainAppWindow() : DocumentWindow (JUCEApplication::getInstance()->getApplicationName(), Colours::lightgrey, DocumentWindow::allButtons) { setResizable(true, false); centreWithSize(getParentWidth(), getParentHeight()); setVisible (true); }

but it doesnt fix it.

beforehand i get a window, if i rotate left, rotate right, left, right etc. it “walks” off the screen sideways to the left. with the new changes, it walks off to the bottom.

anyhow, perhaps this is a different problem altogether :slight_smile:

– hugh.


#5

There is no code intended for auto re-positioning of the peer component excepted for the changed default where I get the old relative centre position over the old desktop and set it at same relative position inside the new desktop.
If this doesn’t fit your needs you should catch the peer’s resized event an reposition your component as you need there.

I’m not developing a standalone app. I’m attaching to an existing peer created by the main application (I’m developing a static library as an extension if the main app) and then adding new peers to the Desktop when required.
So I suppose my context could be slightly different.

As soon as I’ll have released my work I’ll investigate the standard introjucer generated standalone app as well.
More on that: I’m using the latest Juce 2 gitted version, not the last formal release, if that makes any difference…

Alf


#6

Much appreciated, chaps, I’ve had a play around with this and checked some stuff in - let me know if it sorts out your problems…


#7

I anyone still getting trouble with this? I’m using the latest Juce Git code and I’m getting weird coordinates also. The display is correctly rotated when the iPad rotates, but the dimensions and position of the parent window are wrong when the iPad is horizontal. Any help would be appreciated.