Popovers (my solution)

Hi all,

I’ve been wanting popovers for a while and decided to write something that works on Mac and Windows. I only started a couple of days ago so be kind if it sucks…I’d like to improve it. :slight_smile: I’ve developed it on Mac and have tested it in Windows 7 running in Parallels. I’m especially curious to know how it works in other versions of Windows.

You can get the code (with sample project) here:
https://bitbucket.org/wbgookin/gspopoverwindow

You design the popover as a “Plain Box” window type, set its super to GSPopoverWindow, make sure “Resizeable” is false if you’re on Windows, and go. It does some basic automatic placement of where the pointer part goes so if you click in a corner of the screen your window is still visible. And the example I have uses AddHandler to connect TextAreas on the popover to controls on the main window, so as you type it updates the main window too. I’m sure there are other solutions and I’d love to hear them.

A quick screenshot (on mac, running in the IDE):

Also, I’m happy to have other contributors to it, I just don’t know the best way to do that.

Let me know how it works for you…
Bill

1 Like

Looks/works fine in Windows 8. In Windows XP the default window background (brown/grey) and the popup (grey) kind of clash but otherwise it worked as I expected there too.

Nice work!

Bill…don’t commit projects saved in betas :wink: good work though.

Bob - thanks. The popup background is customizable, so perhaps I could base it on whatever the default window background is and darken it a shade or two.

Matthew - oops. :slight_smile:

Bill, this is very cool, great work. I’m trying to make it so the popover window follows the mouse. The “triangle tip” does follow the mouse correctly, however the rest of the window does not and extends infinitely to the right. All that added was a timer on the main window along with a property “poplin” that stores the Popover. Then the timer updates the popover’s position if it exists with your displayPopoverAt method. Do you have a better built in way to make the popover follow the mouse or an idea on how this could be done?

Screen.mousex & screen.mousey in relation to position on the application possibly? A timer wouldn’t work so well. I was adding gradient styles to the class earlier and seems to work quite well so far. Will definately submit publicly when completed.

Yes thats what the timer is doing, setting the position of the popover to the mouseX and mouseY positions using the displayPoppverAt method, but it caused the contents of the window to move to the right or left, up or down, depending on the placement of the mouse in the screen.

The displayPopoverAt shifts all the controls on the screen every time it’s called.

The popover that’s displayed is a little bigger than the window you design because of the pointer. What displayPopoverAt does is make the window a little bigger than you designed it to allow for the pointer to be drawn, then shifts the controls to keep them centered in the main “body” of the popover window. So when you call it over and over, it keeps expanding the window and shifting the controls away from where the pointer is. I would add a “movePopover” routine that just updates self.left and self.top rather than redisplaying it.

One question - if you want to keep the popover stuck to the mouse pointer, how will you ever get it to go away…keyboard?

I updated the routines so if you call displayPopoverAt once it’s already shown, it won’t recreate itself…it just moves. On winPop (the popover that comes up when you click anywhere in the window) there’s now a button captioned “Move Me” that will randomly move the popover around the screen when you click it.

I was thinking I would have it follow the mouse around in an OpenGL surface and give info on certain objects displayed there. I was just going to hide the popover with escape. I think I should be able to get this too work, my first tests look good. One small bug I have noticed is when the popover is displayed and the window is then triple clicked away from the popover a new popover appears and the main window is sent to the back, it disappears behind the IDE but the popover remains on top and active. I’m on Mac in case that matters. This is only a minor bug but I figured I would bring it to your attention.

I have seen that happen, although I hadn’t figured out how to reproduce it (it turns out I only have to double click, not triple). Now that I can reproduce it, I’m not sure what’s causing it. I’ll look it in a bit. Thanks!

Very good work, i try to add a shadow at popover window!

Thanks
Toni

Bill, this is a nice work.
Just a couple of suggestions:

The background and border colors are best defined using the FillColor and FrameColor methods from Xojo.

The border is not displayed on Windows (at least on XP). To get rid of the dark border on Windows, without shrinking the round rectangle, just use this in the open event of the window:

    Const SWP_NOMOVE = &H2
    Const SWP_FRAMECHANGED = &H20
    Const HWND_TOP = 0
    Const GWL_STYLE = -16
    Const WS_POPUPWINDOW = &H80880000
    const WS_MINIMIZEBOX = &h00020000
    
    Dim styleFlags As Integer
    
    Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongW" (hwnd As Integer, nIndex As Integer, dwNewLong As Integer) As Integer
    Declare Function SetWindowPos Lib "user32" (hwnd as Integer, hWndInstertAfter as Integer, x as Integer, y as Integer, cx as Integer, cy as Integer, flags as Integer) as Integer
    
    styleFlags = SetWindowLong( self.WinHWND, GWL_STYLE, WS_POPUPWINDOW )
    styleFlags = SetWindowLong( self.WinHWND, GWL_STYLE, WS_MINIMIZEBOX)
    styleFlags = BitwiseOr( SWP_FRAMECHANGED, SWP_NOMOVE )
    styleFlags = SetWindowPos( self.handle, HWND_TOP, 0, 0, self.width, self.height, styleFlags )

On Mac the corners of the round rectangle are a little bit pixellated

Keep up the good work.

[quote=53179:@Massimo Valle]To get rid of the dark border on Windows, without shrinking the round rectangle, just use this in the open event of the window:
[/quote]

Ahh, thank you!

[quote=53179:@Massimo Valle]
The background and border colors are best defined using the FillColor and FrameColor methods from Xojo.[/quote]

Also, thanks for this. I don’t know how I didn’t know about FillColor before…perhaps it wasn’t there when I first needed it and I never thought to look again. Or perhaps I never read the manual. :slight_smile:

Updated to use the Windows declares that remove the border rather than shrinking the roundrect, and to base the popover color on FillColor rather than hard code a grey.

Still no clue why double clicking on the main window (after a popover is visible) would make the main window drop behind all other windows…anyone? (Edit: on Mac, at least)

This will give the Popover window the proper animation when it becomes visible (at least on Mac OS X)

[code]Sub Constructor()
#if TargetCocoa
Declare Sub setAnimationBehavior lib “AppKit” selector “setAnimationBehavior:” (windowRef As WindowPtr, newAnimationBehavior As Integer)
setAnimationBehavior self, 5
#endif

// Calling the overridden superclass constructor.
Super.Constructor
End Sub[/code]

There is a problem with the border. On Windows (XP at least) the window has no border, while on Mac it has.
Setting Border = 100 on setWindowShape will then draw a border on Windows but the size of the region is smaller by 1 pixel (w and h). However the border radius on corners is different from the fill. On Mac, then a double border is drawn :frowning:

Perhaps I’m not thinking of the word border in the same way, but I don’t have a border when I run it on my Mac, nor do I want one. Can you post a screenshot? I have a feeling I’m about to feel dumb. LOL

You can see two things here:

  • The Mac version has a thin nice border all around the popover shape, while the Windows one has no border and thus it’s confused with the main window.
  • The region cut for Windows doesn’t match with the picture.