how to place a window right next to a widget

Hello all,

I am trying to place a window with a listctrl next to a
widget derived from a textctrl. On Linux/Windows I am using
a PopupWindow. On MacOSX I use a wxWindow instead (I am
aware others use wxFrame as a PopupWindow replacement).

Both are instantiated in the __init__ of the TextCtrl and
are passed the TextCtrl's parent as their parent:

  try:
    self.__picklist_dropdown = wx.PopupWindow(parent)
    add_picklist_to_sizer = False
  except NotImplementedError:
    # on MacOSX wx.PopupWindow is not implemented
    self.__picklist_dropdown = wx.Window(parent=parent, style = wx.SIMPLE_BORDER)
    szr_scroll = wx.BoxSizer(wx.VERTICAL)
    self.__picklist_dropdown.SetSizer(szr_scroll)
    add_picklist_to_sizer = True

  if add_picklist_to_sizer:
    szr_scroll.Add(self._picklist, 1, wx.EXPAND)

Later on, when the window is to be shown the best size and
position are calculated (pw stands for phrasewheel which is
the textctrl):

  # recalculate size
  rows = len(self.__current_matches)
  if rows < 2: # 2 rows minimum
    rows = 2
  if rows > 20: # 20 rows maximum
    rows = 20
  dropdown_size = self.__picklist_dropdown.GetSize()
  pw_size = self.GetSize()
  dropdown_size.SetWidth(pw_size.width)
  dropdown_size.SetHeight((pw_size.height * rows) + 4) # adjust for border width

  # recalculate position
  (pw_x_abs, pw_y_abs) = self.ClientToScreenXY(0,0)
  dropdown_new_x = pw_x_abs
  dropdown_new_y = pw_y_abs + pw_size.height
  self.mac_log('desired dropdown position (on screen): x:%s-%s, y:%s-%s' % (dropdown_new_x, (dropdown_new_x+dropdown_size.width), dropdown_new_y, (dropdown_new_y+dropdown_size.height)))
  self.mac_log('desired dropdown size: %s' % dropdown_size)

  # reaches beyond screen ?
  if (dropdown_new_y + dropdown_size.height) > self._screenheight:
    self.mac_log('dropdown extends offscreen (screen max y: %s)' % self._screenheight)
    max_height = self._screenheight - dropdown_new_y - 4
    self.mac_log('max dropdown height would be: %s' % max_height)
    if max_height > ((pw_size.height * 2) + 4):
      dropdown_size.SetHeight(max_height)
      self.mac_log('possible dropdown position (on screen): x:%s-%s, y:%s-%s' % (dropdown_new_x, (dropdown_new_x+dropdown_size.width), dropdown_new_y, (dropdown_new_y+dropdown_size.height)))
      self.mac_log('possible dropdown size: %s' % dropdown_size)

  # now set dimensions
  self.__picklist_dropdown.SetSize(dropdown_size)
  self._picklist.SetSize(self.__picklist_dropdown.GetClientSize())
  self.mac_log('dropdown size set to: %s' % self.__picklist_dropdown.GetClientSize())
  self.__picklist_dropdown.MoveXY(dropdown_new_x, dropdown_new_y)

Now, on Linux/Windows this works nicely, the dropdown
windows is placed right below the textctrl. On MacOSX,
however, it is placed way off.

One thing I am uncertain about is the MoveXY() call. Note
that the dropdown_new_x and *_new_y are absolute screen
coordinates -- they initially come from the
ClientToScreenXY() call to the phrasewheel textctrl. They
may need to be mapped to the parent windows relative
coordinate system, perhaps. Strange, though, why it does
work on Linux/Windows.

(self.mac_log is simply a MacOSX-specific logging wrapper as
we first noticed this on Mac - however, the problem
manifests itself on Linux, too, when forced to use a
wxWindow instead of the PopupWindow)

The full source of the phrasewheel class is here:

  http://cvs.savannah.gnu.org/viewvc/gnumed/gnumed/client/wxpython/gmPhraseWheel.py?root=gnumed&view=log

The file can be run with "python gmPhraseWheel.py" to call
up a widget test (if you've got a local copy of the CVS tree).

Any help would be appreciated,
Karsten

···

--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

Apparently, a wx.PopupWindow() wants absolute screen
coordinates in MoveXY() regardless of what's the parent
while a wx.Window wants coordinates relative to its
parent...

Robin, would that make sense ?

Karsten

···

On Sat, Apr 26, 2008 at 11:26:00AM +0200, Karsten Hilbert wrote:

I am trying to place a window with a listctrl next to a
widget derived from a textctrl. On Linux/Windows I am using
a PopupWindow. On MacOSX I use a wxWindow instead (I am
aware others use wxFrame as a PopupWindow replacement).

--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

I eventually suspected as much. The assumption seemed to fix
the misbehaviour and now the assumption is verified.

Thanks,
Karsten

···

On Sat, Apr 26, 2008 at 12:11:44PM -0700, Robin Dunn wrote:

Apparently, a wx.PopupWindow() wants absolute screen
coordinates in MoveXY() regardless of what's the parent
while a wx.Window wants coordinates relative to its
parent...

Yes. wx.PopupWindow is essentially a top-level window (like wx.Frame)
so it always uses screen coordinates. wx.Window is always a child of
some other window, so it uses client coordinates.

--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346