CallOutBox question


#1

How can I always have a CallOutBox point to an area x pixels below it, or x pixels above it, regardless of the sizeof the CallOutBox?

In other words I always want the arrow pointing up or down, using UpdatePosition and have the arrow centered horizontally within the Box.

Please show it it code and not theory.
I have been trying for four hours and I can not get it to work consistently.


#2

This isn’t an answer to the question, but is a related comment about CallOutBox behaviour; I spent a good few hours one night trying to figure out why sometimes the box would appear with its pointy arrow, and sometimes it would just appear in front of (i.e. obscuring) the source area, with no pointy arrow. After a few hours I decided to just change to allowing the box to be added to the desktop, and my troubles went away.

There is something dodgy happening in the path it takes to work out the positioning when using a specific parent component; alas, since I found a temporary solution, I didn’t bother to make a simple test case and report it, and then I forgot about it. I’ll eventually knock one up and demand a fix :wink: since I’ll definitely need to change to using a parent component again at some stage.

[size=8]FWIW, I was using a TableListBox, and showing a CallOutBox when clicking on cells. Depending on the size of the window, certain columns would always have their clicked cell hidden behind the box (with no arrow); resizing the window changed which columns had the problem (sometimes none of them).
[/size]


#3

Thanks again Haydxn,

I am doing the same. My CallOutBox is added to the desktop and all area coordinates are global. Sometimes the arrow appears and sometimes it doesn’t. I can get the area to appear, then scale the rects to a bigger size and then arrow disappears. I can’t quite grasp what is going on underneath, but this should be a simple. Playing around I wrote some nasty code that hacked at it until I got it to work for my needs. Apparently the newAreaToPointTo has to be contained inside the newAreaToFitIn and there has to be enough distance between them to allow for an arrow, and the CallOutBox can’t be small, etc.

Jules, how can we create a CallOutBox and point the arrow and a distance x pixels above or below it?


#4

I had to wrestle with this issue again today, so I finally decided to figure out what is going on and where the problem is (since it was driving me absolutely mental!).

The problem appears to be with this bit of CallOutBox::updatePosition() (when iterating over the edges):

if (! (centrePointArea.contains (lines[i].getStart()) || centrePointArea.contains (lines[i].getEnd())))
    distanceFromCentre += 1000.0f;

It's only checking for either endpoint not being contained withing the centrePointArea; as the new bounds get bigger, this becomes increasingly inevitable for all edges.

If I change this to instead test for the line not intersecting the centrePointArea, it behaves as I would expect.

 


#5

I guess this would also be a reasonable place to ask if there's any chance of a nice helper Rectangle::isIntersectedBy(Line) or equivalent function to simplify something like this :) 


#6

I guess this would also be a reasonable place to ask if there's any chance of a nice helper Rectangle::isIntersectedBy(Line) or equivalent function to simplify something like this :)

You could do this:

myRectangle.toPath().intersectsLine (myLine)


#7

Of course :D I was next going to ask for perhaps Rectangle::getTopEdge() etc.. to make the manual testing neater, but that works too, thanks!

I guess the 'any chance of an official CallOutBox fix?' comment is implied, but I may as well add it all the same just in case ;)


#8

(Sorry, I somehow completely failed to read the start of this thread!)

Ok.. I don't have a test-case to see what happens myself, but you're saying that changing it to this:

        Path p;
        p.addRectangle (centrePointArea);
        if (! p.intersectsLine (lines[i]))
            distanceFromCentre += 1000.0f;

..fixes whatever situations you guys are struggling with?


#9

That looks equivalent to my fix, so it should address the main issue :) I can whip up a simple demo to prove/verify it though! The easiest way to see it is to just show a box that is taller than half the height of the desktop; the 'valid centre' rectangle becomes very thin, so it's quite likely that none of the tested points will ever lie within it unless the 'target area' is near the very bottom or top.

I think the original post may have also been requesting the ability to specify a preference for vertical alignment, though the key issue was definitely that the box would tend to overlap the target area despite there being plenty of space to sit in.


#10

In fact, it's quite easy to test with the CallOutBox example on the Dialog Boxes page of the new Demo app.  

There are two ways to see the problem;

1) Set your desktop resolution really low  (e.g. my MBP goes down to 1024x640) and run it as-is; if you move the window so that the 'CalloutBox' button is near the centre of the screen and click it, the box will appear in front of the button.

2) Alternatively, change line #211 to this (so it is a child of the window instead of the desktop)...

CallOutBox::launchAsynchronously (colourSelector, button.getBoundsInParent(), this);

... and experiment with clicking the button at various window heights.


#11

Ok, well, it seems to work pretty well with Haydxn's suggestion - I'll roll that out. Thanks all!


#12

I'm trying to show a CallOutBox positioned inside the main app window, so I write

Component*        c = new Component();
Rectangle<int>    refArea   = buttonThatWasClicked->getScreenBounds(),
                  fitInArea = mainContentPanel->getScreenBounds();

c->setSize(200, 400);

CallOutBox::launchAsynchronously(c, refArea, nullptr)
     .updatePosition(refArea, fitInArea);

'buttonThatWasClicked' is positioned near the bottom margin of the window. If I don't call updatePosition(), the callout is positioned by the right side of the button and vertically the centerline of the button and the callout are aligned.

I see 2 problems:

1. The arrow is initially shown on the left side of the callout, in agreement with the initial position of the callout. This could be avoided if the 'fitInArea' parameter could be specified before the callout were created.

2. Immediately after, the arrow disappears.


#13

It would also be necessary to have an official way to programmatically close a CallOutBox.  I'm currently using

box->postCommandMessage(0x4f83a04b);

since that number corresponds to the callOutBoxDismissCommandId constant that is defined in the CallOutBox code, but not accessible.


#14

Just calling setVisible (false) or exitModalState(0) would do the job, there's no need for a special function.


#15

I'm struggling to see the problem - I tested calloutboxes when I was working on the new demo, and they now seem to be well-positioned in all the cases I could find. If you can give me a piece of code which reliably gets it wrong, please let me know and I'll try it.


#16

OK, now I understand. I have attached a sketch that references the code above. In practice refArea must be contained within fitInArea. Is this the expected behaviour?


#17

Understood, thanks!


#18

Ah yes - all bets are off if you tell it to point to something and then constrain it so that it can't get near to it!