wxWidgets for Mac has no support for wxPopupWindow. Here is a workaround.
Replace infowindow.h and infowindow.cpp with the following.
/*
* Objects of type InfoWindow are autonomous and must therefore always be instantiated using operator new.
* In addition to this, InfoWindow does not have any non-static public class members.
*
* Since a (technically 100% correct) statement like
* new InfoWindow("foo", "bar");
* is unintuitive, confusing or even objective to some people, this class uses a variation of the "Named Constructor Idiom".
*
* InfoWindow::Display("foo", "bar");
* does the exact same thing as the above statement but looks a lot nicer.
*/
#ifndef INFOWINDOW_H
#define INFOWINDOW_H
//#define __WXMAC__
//-----------------------------------------------------------------------------
#if (defined(__WXMAC__) || defined(_TEST_NO_INFOWINDOW_))
//-----------------------------------------------------------------------------
// There is no wxPopupWindows for wxMac. Use wxMessageBox instead.
class InfoWindow : public wxWindow
{
public:
InfoWindow(const wxString& title, const wxString& message, unsigned int delay, unsigned int hysteresis)
{ ::wxMessageBox(message, title, wxOK, NULL, -1, -1);
Destroy();
}
~InfoWindow() {;}
static void Display(const wxString& title, const wxString& message, unsigned int delay = 5000, unsigned int hysteresis = 1)
{ new InfoWindow(title, message, delay, hysteresis);}
};
#endif //(_WXMAC_)
//-----------------------------------------------------------------------------
#if (!defined(__WXMAC__) && !defined(_TEST_NO_INFOWINDOW_))
//-----------------------------------------------------------------------------
#include <wx/event.h>
#include <wx/timer.h>
#include <wx/string.h>
#include <wx/popupwin.h>
#undef new
#include <list>
#include <algorithm>
class Stacker
{
std::list<int> widths;
public:
int StackMe(int mySize)
{
mySize += 3;
int pos = 0;
if(!widths.empty())
pos = *(std::max_element(widths.begin(), widths.end()));
widths.push_back(pos + mySize);
return pos + mySize;
};
void ReleaseMe(int myPos)
{
std::list<int>::iterator it = std::find(widths.begin(), widths.end(), myPos);
if(it != widths.end())
widths.erase(it);
};
};
class InfoWindow : public wxPopupWindow
{
wxTimer *m_timer;
int left;
int top;
int hMin;
int pos;
unsigned int status;
unsigned int m_delay;
unsigned int ks;
static Stacker stacker;
static int screenWidth;
static int screenHeight;
InfoWindow(const wxString& title, const wxString& message, unsigned int delay, unsigned int hysteresis);
virtual ~InfoWindow();
void OnTimer(wxTimerEvent& e);
void OnMove(wxMouseEvent& e);
void OnClick(wxMouseEvent& e);
DECLARE_EVENT_TABLE()
public:
static void Display(const wxString& title, const wxString& message, unsigned int delay = 5000, unsigned int hysteresis = 1)
{new InfoWindow(title, message, delay, hysteresis);};
};
#endif //!defined( _WX_MAC_)
#endif
#include "sdk_precomp.h"
// --------------------------------------------------------------------------
#if (!defined(__WXMAC__) && !defined(_TEST_NO_INFOWINDOW_))
// --------------------------------------------------------------------------
#ifndef CB_PRECOMP
#include <wx/stattext.h>
#include <wx/sizer.h>
#include <wx/settings.h>
#include "infowindow.h"
#include "manager.h"
#endif
BEGIN_EVENT_TABLE(InfoWindow, wxPopupWindow)
EVT_TIMER(-1, InfoWindow::OnTimer)
EVT_MOTION(InfoWindow::OnMove)
EVT_LEFT_DOWN(InfoWindow::OnClick)
EVT_RIGHT_DOWN(InfoWindow::OnClick)
END_EVENT_TABLE()
const wxColour titleBackground(96,96,96); // dark grey
const wxColour textBackground(255,255,160); // yellowish
const char *iBitmap[] = {
"20 20 38 1",
" c #606060",
". c gray38",
"X c #646464",
"o c #656565",
"O c gray40",
"+ c gray45",
"@ c gray50",
"# c blue",
"$ c #0808FF",
"% c #0A0AFF",
"& c #0B0BFF",
"* c #2121FF",
"= c #2828FF",
"- c #3838FF",
"; c #4545FF",
": c #4646FF",
"> c #5656FF",
", c #5959FF",
"< c gray51",
"1 c #8E8E8E",
"2 c gray59",
"3 c #9191A7",
"4 c #8888EF",
"5 c #8080F7",
"6 c #8282F7",
"7 c #8787FE",
"8 c #8A8AFE",
"9 c #9696FE",
"0 c #9797FF",
"q c #ABABFF",
"w c #CDCDFF",
"e c #D5D5FF",
"r c #E4E4F9",
"t c gray96",
"y c #F6F6F6",
"u c gray97",
"i c #F8F8F8",
"p c gray100",
" X+<1221<+O ",
" X+35,=&&=,63+X ",
" X@4:########:4@X ",
" X@5*#&>0ww0,&#*5@X ",
" +4*#-qppppppq:#*4+ ",
"X3:#:eppp##pppe:#:3X",
"+6#&qpppp##ppppq+",
"<,#,ppppp##ppppp,#,@",
"1=#9ppppp##ppppp0#=1",
"2&#wppppp##pppppw#&2",
"i&#wppppp##pppppw#&u",
"i=#9ppppp##ppppp0#=u",
"u,#>pppppppppppp>#,y",
"y8#&qpppp##ppppq$#8y",
"yr:#:eppp##pppe:#:rt",
"yy9*#:qppppppq:#*9yt",
"yyy7*#$>0ww0>&#*7ytt",
"ttyy9:########:9yytt",
"ttttyr8,=&&=,8ryyttt",
"ttttyyyyiuuuuyyyyttt"
};
Stacker InfoWindow::stacker;
// in wxGTK this initialization raises an assertion (makes sense too)
// so initialize them to -1 and we 'll set them up correctly in InfoWindow's ctor the first time
int InfoWindow::screenWidth = -1;//wxSystemSettings::GetMetric(wxSYS_SCREEN_X);
int InfoWindow::screenHeight = -1;//wxSystemSettings::GetMetric(wxSYS_SCREEN_Y);
namespace // anonumous
{
// while in windows world, sleep(1) takes anywhere between 20-50 milliseconds,
// in linux sleep(1) means sleep 1 millisecond.
// so we need conditional compilation here in order for the scrolling effect to be
// visible under non-windows platforms :)
#ifdef __WXMSW__
static const int scroll_millis = 1;
#else
static const int scroll_millis = 5;
#endif
} // anonumous namespace
class ForwardingTextControl : public wxStaticText
{
void OnEvent(wxMouseEvent& e){e.ResumePropagation(10); e.Skip();};
DECLARE_EVENT_TABLE();
public:
ForwardingTextControl(wxWindow* parent, wxWindowID id, const wxString& label, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0) : wxStaticText(parent, id, label, pos, size, style){};
};
BEGIN_EVENT_TABLE(ForwardingTextControl, wxStaticText)
EVT_MOUSE_EVENTS(ForwardingTextControl::OnEvent)
END_EVENT_TABLE()
InfoWindow::InfoWindow(const wxString& title, const wxString& message, unsigned int delay, unsigned int hysteresis)
: wxPopupWindow(Manager::Get()->GetAppWindow(), wxSIMPLE_BORDER | wxWS_EX_TRANSIENT | wxCLIP_CHILDREN),
m_timer(new wxTimer(this, 0)), status(0), m_delay(delay), ks(2)
{
wxBoxSizer *bs = new wxBoxSizer(wxVERTICAL);
wxWindow* o = 0;
#ifdef __WXGTK__
wxBoxSizer *pbs = new wxBoxSizer(wxVERTICAL);
wxPanel* pnl = new wxPanel(this, -1, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
pnl->SetBackgroundColour(titleBackground);
ForwardingTextControl *titleC = new ForwardingTextControl(pnl, -1, title, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
pbs->Add(titleC, 0, wxALL|wxALIGN_CENTER, 5);
pnl->SetSizer(pbs);
pbs->SetSizeHints(pnl);
o = pnl;
#else
ForwardingTextControl *titleC = new ForwardingTextControl(this, -1, title, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
titleC->SetBackgroundColour(titleBackground);
o = titleC;
#endif
titleC->SetForegroundColour(*wxWHITE);
titleC->SetFont(wxFont(11, wxSWISS, wxNORMAL, wxBOLD));
bs->Add(o, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5);
ForwardingTextControl *text = new ForwardingTextControl(this, -1, message, wxDefaultPosition, wxDefaultSize, 0);
text->SetBackgroundColour(textBackground);
bs->Add(text, 0, wxALIGN_CENTER|wxALL, 12);
SetBackgroundColour(textBackground);
SetSizer(bs);
bs->SetSizeHints(this);
Layout();
#ifndef __WXGTK__
// since we used a panel, no more bitmap :(
new wxStaticBitmap(this, -1, wxBitmap(iBitmap), wxPoint(4, o->GetRect().GetBottom() - 9));
#endif
wxCoord w, h;
GetClientSize(&w, &h);
pos = stacker.StackMe(w);
// setup variables first time we enter here
if (screenWidth == -1)
screenWidth = wxSystemSettings::GetMetric(wxSYS_SCREEN_X);
if (screenHeight == -1)
screenHeight = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y);
left = screenWidth - pos;
hMin = screenHeight - h;
top = screenHeight;
Move(left, top);
Show();
m_timer->Start(hysteresis, false);
};
InfoWindow::~InfoWindow()
{
delete m_timer;
stacker.ReleaseMe(pos);
};
void InfoWindow::OnTimer(wxTimerEvent& e)
{
switch(status)
{
case 0:
status = 1;
m_timer->Start(scroll_millis, false);
break;
case 1:
top -= 2;
Move(left, top);
if(top <= hMin)
{
status = 2;
m_timer->Start(m_delay, true);
}
break;
case 2:
status = 3;
m_timer->Start(scroll_millis, false);
break;
case 3:
top += ks;
Move(left, top);
if(top > screenHeight)
{
Hide();
Destroy();
}
break;
};
};
void InfoWindow::OnMove(wxMouseEvent& e)
{
if(status == 2)
m_timer->Start(m_delay, true);
}
void InfoWindow::OnClick(wxMouseEvent& e)
{
ks = 6;
status = 3;
m_timer->Start(scroll_millis, false);
}
// --------------------------------------------------------------------------
#endif //!defined(__WXMAC__)
// --------------------------------------------------------------------------
I have not tested this extensively, but I have forced it to execute on both windows and OS X 10.3.
I will make a patch as soon as I'm certain it works on all platforms.