Files
wxWidgets/src/univ/topluniv.cpp
2001-11-21 00:03:56 +00:00

562 lines
16 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: topluniv.cpp
// Author: Vaclav Slavik
// Id: $Id$
// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "univtoplevel.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/defs.h"
#ifndef WX_PRECOMP
#include "wx/dcclient.h"
#include "wx/settings.h"
#endif
#include "wx/toplevel.h"
#include "wx/univ/renderer.h"
#include "wx/bitmap.h"
#include "wx/image.h"
#include "wx/cshelp.h"
// ----------------------------------------------------------------------------
// event tables
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(wxTopLevelWindow, wxTopLevelWindowNative)
WX_EVENT_TABLE_INPUT_CONSUMER(wxTopLevelWindow)
EVT_NC_PAINT(wxTopLevelWindow::OnNcPaint)
END_EVENT_TABLE()
WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow)
// ============================================================================
// implementation
// ============================================================================
int wxTopLevelWindow::ms_drawDecorations = -1;
int wxTopLevelWindow::ms_canIconize = -1;
void wxTopLevelWindow::Init()
{
m_isActive = FALSE;
m_windowStyle = 0;
m_pressedButton = 0;
}
bool wxTopLevelWindow::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString &name)
{
// init them to avoid compiler warnings
long styleOrig = 0,
exstyleOrig = 0;
if ( ms_drawDecorations == -1 )
{
ms_drawDecorations =
!wxSystemSettings::GetCapability(wxSYS_CAN_DRAW_FRAME_DECORATIONS)
|| wxGetEnv(wxT("WXDECOR"), NULL);
// FIXME -- wxUniv should provide a way to force non-native decorations!
// $WXDECOR is just a hack in absence of better wxUniv solution
}
if ( ms_canIconize == -1 )
{
ms_canIconize = wxSystemSettings::GetCapability(wxSYS_CAN_ICONIZE_FRAME);
}
if ( ms_drawDecorations )
{
CreateInputHandler(wxINP_HANDLER_TOPLEVEL);
styleOrig = style;
exstyleOrig = GetExtraStyle();
style &= ~(wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
wxSYSTEM_MENU | wxRESIZE_BORDER | wxFRAME_TOOL_WINDOW |
wxTHICK_FRAME);
style = wxSIMPLE_BORDER;
SetExtraStyle(exstyleOrig &
~(wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP));
}
if ( !wxTopLevelWindowNative::Create(parent, id, title, pos,
size, style, name) )
return FALSE;
if ( ms_drawDecorations )
{
m_windowStyle = styleOrig;
m_exStyle = exstyleOrig;
}
return TRUE;
}
bool wxTopLevelWindow::ShowFullScreen(bool show, long style)
{
if ( show == IsFullScreen() ) return FALSE;
if ( ms_drawDecorations )
{
if ( show )
{
m_fsSavedStyle = m_windowStyle;
if ( style & wxFULLSCREEN_NOBORDER )
m_windowStyle |= wxSIMPLE_BORDER;
if ( style & wxFULLSCREEN_NOCAPTION )
m_windowStyle &= ~wxCAPTION;
}
else
{
m_windowStyle = m_fsSavedStyle;
}
}
return wxTopLevelWindowNative::ShowFullScreen(show, style);
}
long wxTopLevelWindow::GetDecorationsStyle() const
{
long style = 0;
if ( m_windowStyle & wxCAPTION )
{
style |= wxTOPLEVEL_TITLEBAR | wxTOPLEVEL_BUTTON_CLOSE;
if ( (m_windowStyle & wxMINIMIZE_BOX) && ms_canIconize )
style |= wxTOPLEVEL_BUTTON_ICONIZE;
if ( m_windowStyle & wxMAXIMIZE_BOX )
{
if ( IsMaximized() )
style |= wxTOPLEVEL_BUTTON_RESTORE;
else
style |= wxTOPLEVEL_BUTTON_MAXIMIZE;
}
#if wxUSE_HELP
if ( m_exStyle & (wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP))
style |= wxTOPLEVEL_BUTTON_HELP;
#endif
}
if ( (m_windowStyle & (wxSIMPLE_BORDER | wxNO_BORDER)) == 0 )
style |= wxTOPLEVEL_BORDER;
if ( m_windowStyle & (wxRESIZE_BORDER | wxTHICK_FRAME) )
style |= wxTOPLEVEL_RESIZEABLE;
if ( IsMaximized() )
style |= wxTOPLEVEL_MAXIMIZED;
if ( GetIcon().Ok() )
style |= wxTOPLEVEL_ICON;
if ( m_isActive )
style |= wxTOPLEVEL_ACTIVE;
return style;
}
void wxTopLevelWindow::RefreshTitleBar()
{
wxNcPaintEvent event(GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(event);
}
// ----------------------------------------------------------------------------
// client area handling
// ----------------------------------------------------------------------------
wxPoint wxTopLevelWindow::GetClientAreaOrigin() const
{
if ( ms_drawDecorations )
{
int w, h;
wxTopLevelWindowNative::DoGetClientSize(&w, &h);
wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
wxSize(w, h));
rect = m_renderer->GetFrameClientArea(rect,
GetDecorationsStyle());
return rect.GetPosition();
}
else
{
return wxTopLevelWindowNative::GetClientAreaOrigin();
}
}
void wxTopLevelWindow::DoGetClientSize(int *width, int *height) const
{
if ( ms_drawDecorations )
{
int w, h;
wxTopLevelWindowNative::DoGetClientSize(&w, &h);
wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
wxSize(w, h));
rect = m_renderer->GetFrameClientArea(rect,
GetDecorationsStyle());
if ( width )
*width = rect.width;
if ( height )
*height = rect.height;
}
else
wxTopLevelWindowNative::DoGetClientSize(width, height);
}
void wxTopLevelWindow::DoSetClientSize(int width, int height)
{
if ( ms_drawDecorations )
{
wxSize size = m_renderer->GetFrameTotalSize(wxSize(width, height),
GetDecorationsStyle());
wxTopLevelWindowNative::DoSetClientSize(size.x, size.y);
}
else
wxTopLevelWindowNative::DoSetClientSize(width, height);
}
void wxTopLevelWindow::OnNcPaint(wxPaintEvent& event)
{
if ( !ms_drawDecorations || !m_renderer )
event.Skip();
else
{
// get the window rect
wxRect rect;
wxSize size = GetSize();
rect.x =
rect.y = 0;
rect.width = size.x;
rect.height = size.y;
wxWindowDC dc(this);
m_renderer->DrawFrameTitleBar(dc, rect,
GetTitle(), m_titlebarIcon,
GetDecorationsStyle(),
m_pressedButton,
wxCONTROL_PRESSED);
}
}
long wxTopLevelWindow::HitTest(const wxPoint& pt) const
{
int w, h;
wxTopLevelWindowNative::DoGetClientSize(&w, &h);
wxRect rect(wxTopLevelWindowNative::GetClientAreaOrigin(), wxSize(w, h));
return m_renderer->HitTestFrame(rect, pt+GetClientAreaOrigin(), GetDecorationsStyle());
}
// ----------------------------------------------------------------------------
// icons
// ----------------------------------------------------------------------------
void wxTopLevelWindow::SetIcon(const wxIcon& icon)
{
wxTopLevelWindowNative::SetIcon(icon);
if ( ms_drawDecorations && m_renderer )
{
wxSize size = m_renderer->GetFrameIconSize();
if ( !icon.Ok() || size.x == -1 )
m_titlebarIcon = icon;
else
{
wxBitmap bmp1;
bmp1.CopyFromIcon(icon);
if ( !bmp1.Ok() )
m_titlebarIcon = wxNullIcon;
else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
m_titlebarIcon = icon;
else
{
wxImage img = bmp1.ConvertToImage();
img.Rescale(size.x, size.y);
m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
}
}
}
}
// ----------------------------------------------------------------------------
// actions
// ----------------------------------------------------------------------------
void wxTopLevelWindow::ClickTitleBarButton(long button)
{
switch ( button )
{
case wxTOPLEVEL_BUTTON_CLOSE:
Close();
break;
case wxTOPLEVEL_BUTTON_ICONIZE:
Iconize();
break;
case wxTOPLEVEL_BUTTON_MAXIMIZE:
Maximize();
break;
case wxTOPLEVEL_BUTTON_RESTORE:
Restore();
break;
case wxTOPLEVEL_BUTTON_HELP:
#if wxUSE_HELP
{
wxContextHelp contextHelp(this);
}
#endif
break;
default:
wxFAIL_MSG(wxT("incorrect button specification"));
}
}
bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
long numArg,
const wxString& strArg)
{
bool isActive = numArg != 0;
if ( action == wxACTION_TOPLEVEL_ACTIVATE )
{
if ( m_isActive != isActive )
{
m_isActive = isActive;
RefreshTitleBar();
}
return TRUE;
}
else if ( action == wxACTION_TOPLEVEL_BUTTON_PRESS )
{
m_pressedButton = numArg;
RefreshTitleBar();
return TRUE;
}
else if ( action == wxACTION_TOPLEVEL_BUTTON_RELEASE )
{
m_pressedButton = 0;
RefreshTitleBar();
return TRUE;
}
else if ( action == wxACTION_TOPLEVEL_BUTTON_CLICK )
{
m_pressedButton = 0;
RefreshTitleBar();
ClickTitleBarButton(numArg);
return TRUE;
}
else if ( action == wxACTION_TOPLEVEL_MOVE )
{
InteractiveMove(wxINTERACTIVE_MOVE);
return TRUE;
}
else if ( action == wxACTION_TOPLEVEL_RESIZE )
{
int flags = wxINTERACTIVE_RESIZE;
if ( numArg & wxHT_TOPLEVEL_BORDER_N )
flags |= wxINTERACTIVE_RESIZE_N;
if ( numArg & wxHT_TOPLEVEL_BORDER_S )
flags |= wxINTERACTIVE_RESIZE_S;
if ( numArg & wxHT_TOPLEVEL_BORDER_W )
flags |= wxINTERACTIVE_RESIZE_W;
if ( numArg & wxHT_TOPLEVEL_BORDER_E )
flags |= wxINTERACTIVE_RESIZE_E;
InteractiveMove(flags);
return TRUE;
}
else
return FALSE;
}
// ============================================================================
// wxStdFrameInputHandler: handles focus, resizing and titlebar buttons clicks
// ============================================================================
wxStdFrameInputHandler::wxStdFrameInputHandler(wxInputHandler *inphand)
: wxStdInputHandler(inphand)
{
m_winCapture = NULL;
m_winHitTest = 0;
m_winPressed = 0;
m_borderCursorOn = FALSE;
}
bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
// the button has 2 states: pressed and normal with the following
// transitions between them:
//
// normal -> left down -> capture mouse and go to pressed state
// pressed -> left up inside -> generate click -> go to normal
// outside ------------------>
//
// the other mouse buttons are ignored
if ( event.Button(1) )
{
if ( event.ButtonDown(1) )
{
wxTopLevelWindow *w = wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
long hit = w->HitTest(event.GetPosition());
if ( hit & wxHT_TOPLEVEL_ANY_BUTTON )
{
m_winCapture = w;
m_winCapture->CaptureMouse();
m_winHitTest = hit;
m_winPressed = hit;
consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
return TRUE;
}
else if ( hit & wxHT_TOPLEVEL_TITLEBAR )
{
consumer->PerformAction(wxACTION_TOPLEVEL_MOVE);
return TRUE;
}
else if ( (consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER)
&& (hit & wxHT_TOPLEVEL_ANY_BORDER) )
{
consumer->PerformAction(wxACTION_TOPLEVEL_RESIZE, hit);
return TRUE;
}
}
else // up
{
if ( m_winCapture )
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
if ( m_winHitTest == m_winPressed )
{
consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK, m_winPressed);
return TRUE;
}
}
//else: the mouse was released outside the window, this doesn't
// count as a click
}
}
return wxStdInputHandler::HandleMouse(consumer, event);
}
bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
if ( event.GetEventObject() == m_winCapture )
{
long hit = m_winCapture->HitTest(event.GetPosition());
if ( hit != m_winHitTest )
{
if ( hit != m_winPressed )
consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_RELEASE, m_winPressed);
else
consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
m_winHitTest = hit;
return TRUE;
}
}
else if ( consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER )
{
wxTopLevelWindow *win = wxStaticCast(consumer->GetInputWindow(),
wxTopLevelWindow);
long hit = win->HitTest(event.GetPosition());
if ( hit != m_winHitTest )
{
m_winHitTest = hit;
if ( m_borderCursorOn )
{
m_borderCursorOn = FALSE;
win->SetCursor(m_origCursor);
}
if ( hit & wxHT_TOPLEVEL_ANY_BORDER )
{
m_borderCursorOn = TRUE;
wxCursor cur;
switch (hit)
{
case wxHT_TOPLEVEL_BORDER_N:
case wxHT_TOPLEVEL_BORDER_S:
cur = wxCursor(wxCURSOR_SIZENS);
break;
case wxHT_TOPLEVEL_BORDER_W:
case wxHT_TOPLEVEL_BORDER_E:
cur = wxCursor(wxCURSOR_SIZEWE);
break;
case wxHT_TOPLEVEL_BORDER_NE:
case wxHT_TOPLEVEL_BORDER_SW:
cur = wxCursor(wxCURSOR_SIZENESW);
break;
case wxHT_TOPLEVEL_BORDER_NW:
case wxHT_TOPLEVEL_BORDER_SE:
cur = wxCursor(wxCURSOR_SIZENWSE);
break;
default:
m_borderCursorOn = FALSE;
break;
}
if ( m_borderCursorOn )
{
m_origCursor = win->GetCursor();
win->SetCursor(cur);
}
}
}
}
return wxStdInputHandler::HandleMouseMove(consumer, event);
}
bool wxStdFrameInputHandler::HandleActivation(wxInputConsumer *consumer,
bool activated)
{
if ( m_borderCursorOn )
{
consumer->GetInputWindow()->SetCursor(m_origCursor);
m_borderCursorOn = FALSE;
}
consumer->PerformAction(wxACTION_TOPLEVEL_ACTIVATE, activated);
return FALSE;
}