include/cinder/app/Window.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2012, The Cinder Project, All rights reserved.
00003 
00004  This code is intended for use with the Cinder C++ library: http://libcinder.org
00005 
00006  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00007  the following conditions are met:
00008 
00009     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00010     the following disclaimer.
00011     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00012     the following disclaimer in the documentation and/or other materials provided with the distribution.
00013 
00014  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00015  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00016  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00017  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00018  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00019  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00020  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00021  POSSIBILITY OF SUCH DAMAGE.
00022 */
00023 
00024 #pragma once
00025 
00026 #include "cinder/Cinder.h"
00027 #include "cinder/Display.h"
00028 #include "cinder/app/Renderer.h"
00029 #include "cinder/Vector.h"
00030 #include "cinder/Function.h"
00031 #include "cinder/app/MouseEvent.h"
00032 #include "cinder/app/TouchEvent.h"
00033 #include "cinder/app/KeyEvent.h"
00034 #include "cinder/app/FileDropEvent.h"
00035 
00036 namespace cinder { namespace app {
00037 
00038 class Window;
00039 struct FullScreenOptions;
00040 typedef std::shared_ptr<Window>     WindowRef;
00041 
00042 } } // namespace cinder::app
00043 
00044 #if defined( CINDER_COCOA ) && defined( __OBJC__ )
00045     #import <Foundation/Foundation.h>
00046     #if defined( CINDER_COCOA_TOUCH )
00047         @class UIViewController;
00048     #endif
00049 
00050     @protocol WindowImplCocoa
00051         @required
00052         - (BOOL)isFullScreen;
00053         - (void)setFullScreen:(BOOL)fullScreen options:(const cinder::app::FullScreenOptions *)options;
00054         - (cinder::Vec2i)getSize;
00055         - (void)setSize:(cinder::Vec2i)size;
00056         - (cinder::Vec2i)getPos;
00057         - (void)setPos:(cinder::Vec2i)pos;
00058         - (float)getContentScale;
00059         - (void)close;
00060         - (NSString *)getTitle;
00061         - (void)setTitle:(NSString *)title;
00062         - (BOOL)isBorderless;
00063         - (void)setBorderless:(BOOL)borderless;
00064         - (BOOL)isAlwaysOnTop;
00065         - (void)setAlwaysOnTop:(BOOL)alwaysOnTop;
00066         - (void)hide;
00067         - (void)show;
00068         - (BOOL)isHidden;
00069         - (cinder::DisplayRef)getDisplay;
00070         - (cinder::app::RendererRef)getRenderer;
00071         - (const std::vector<cinder::app::TouchEvent::Touch>&)getActiveTouches;
00072         - (void*)getNative;
00073     #if defined( CINDER_COCOA_TOUCH )
00074         - (UIViewController *)getNativeViewController;
00075     #endif
00076     @end
00077 #elif defined( CINDER_COCOA )
00078     class WindowImplCocoa;
00079     #if defined( CINDER_COCOA_TOUCH )
00080         class UIViewController;
00081     #endif
00082 #elif defined( CINDER_MSW )
00083     namespace cinder { namespace app {
00084         class WindowImplMsw;
00085     } } // namespace cinder::app
00086 #endif
00087 
00088 namespace cinder { namespace app {
00089 
00090 typedef  signals::signal<void(MouseEvent&),EventCombiner<MouseEvent> >      EventSignalMouse;
00091 typedef  signals::signal<void(TouchEvent&),EventCombiner<TouchEvent> >      EventSignalTouch;
00092 typedef  signals::signal<void(KeyEvent&),EventCombiner<KeyEvent> >          EventSignalKey;
00093 typedef  signals::signal<void(FileDropEvent&),EventCombiner<FileDropEvent> > EventSignalFileDrop;
00094 typedef  signals::signal<void()>                                            EventSignalWindow;
00095 
00097 class ExcInvalidWindow : public cinder::Exception {
00098     virtual const char * what() const throw() { return "Invalid Window"; }
00099 };
00100 
00102 struct FullScreenOptions {
00103     FullScreenOptions() : mKioskMode( true ), mSecondaryDisplayBlanking( false ), mExclusive( false )
00104     {}
00105 
00107     FullScreenOptions&  kioskMode( bool enable = true )                 { mKioskMode = enable; return *this; }
00109     FullScreenOptions&  secondaryDisplayBlanking( bool enable = true )  { mSecondaryDisplayBlanking = enable; return *this; }
00111     FullScreenOptions&  exclusive( bool enable = true )                 { mExclusive = enable; return *this; }
00113     FullScreenOptions&  display( DisplayRef display )                   { mDisplay = display; return *this; }
00114 
00116     DisplayRef          getDisplay()                                    const { return mDisplay; }
00118     bool                isKioskModeEnabled()                            const { return mKioskMode; }
00120     bool                isSecondaryDisplayBlankingEnabled()             const { return mSecondaryDisplayBlanking; }
00122     bool                isExclusive()                                   const { return mExclusive; }
00123 
00124   private:
00125     DisplayRef  mDisplay;
00126     bool        mKioskMode, mSecondaryDisplayBlanking, mExclusive;
00127 };
00128 
00129 class Window : public std::enable_shared_from_this<Window> {
00130   public:
00131     // Parameters for a Window, which are used to create the physical window by the App
00132     struct Format {
00133         Format( RendererRef renderer = RendererRef(), DisplayRef display = Display::getMainDisplay(), bool fullScreen = false, Vec2i size = Vec2i( 640, 480 ), Vec2i pos = Vec2i::zero() )
00134             : mRenderer( renderer ), mFullScreen( fullScreen ), mDisplay( display ), mSize( size ), mPos( pos ), mPosSpecified( false ),
00135             mResizable( true ), mBorderless( false ), mAlwaysOnTop( false ), mFullScreenButtonEnabled( false )
00136 #if defined( CINDER_COCOA_TOUCH )
00137             , mRootViewController( NULL )
00138 #endif
00139         {
00140             mFullScreenOptions.kioskMode( true );
00141         }
00142 
00144         DisplayRef  getDisplay() const { return mDisplay; }
00146         void        setDisplay( DisplayRef display ) { mDisplay = display; }
00148         Format&     display( DisplayRef displayRef ) { mDisplay = displayRef; return *this; }
00150         bool        isFullScreen() const { return mFullScreen; }
00152         const FullScreenOptions& getFullScreenOptions() const { return mFullScreenOptions; }
00154         void        setFullScreen( bool fullScreen = true, const FullScreenOptions &options = FullScreenOptions() ) { mFullScreen = fullScreen; mFullScreenOptions = options; }
00156         Format&     fullScreen( bool fs = true ) { mFullScreen = fs; return *this; }
00158         Vec2i       getSize() const { return mSize; }
00160         void        setSize( const Vec2i &size ) { mSize = size; }
00162         void        setSize( int32_t width, int32_t height ) { mSize = Vec2i( width, height ); }
00164         Format&     size( const Vec2i &s ) { mSize = s; return *this; }
00166         Format&     size( int32_t width, int32_t height ) { mSize = Vec2i( width, height ); return *this; }
00167 
00169         Vec2i       getPos() const { return mPos; }
00171         void        setPos( const Vec2i &pos ) { mPos = pos; mPosSpecified = true; }
00173         void        setPos( int32_t x, int32_t y ) { mPos = Vec2i( x, y ); mPosSpecified = true; }
00175         Format&     pos( const Vec2i &pos ) { mPos = pos; mPosSpecified = true; return *this; }
00177         Format&     pos( int32_t x, int32_t y ) { mPos = Vec2i( x, y ); mPosSpecified = true; return *this; }
00179         bool        isPosSpecified() const { return mPosSpecified; }
00181         void        unspecifyPos() { mPosSpecified = false; }
00182 
00184         RendererRef getRenderer() const { return mRenderer; }
00186         void        setRenderer( RendererRef renderer ) { mRenderer = renderer; }
00188         Format&     renderer( RendererRef r ) { mRenderer = r; return *this; }
00189 
00190 #if defined( CINDER_COCOA_TOUCH )
00191 
00192         UIViewController*   getRootViewController() { return mRootViewController;}
00194         void                setRootViewController( UIViewController *v ) { mRootViewController = v; }
00196         Format&             rootViewController( UIViewController *v ) { mRootViewController = v; return *this; }
00197 #endif
00198 
00200         bool        isResizable() const { return mResizable; }
00202         void        setResizable( bool resizable = true ) { mResizable = resizable; }
00204         Format&     resizable( bool res = true ) { mResizable = res; return *this; }
00206         bool        isBorderless() const { return mBorderless; }
00208         void        setBorderless( bool borderless = true ) { mBorderless = borderless; }
00210         Format&     borderless( bool border = true ) { mBorderless = border; return *this; }
00212         bool        isAlwaysOnTop() const { return mAlwaysOnTop; }
00214         void        setAlwaysOnTop( bool alwaysOnTop = true ) { mAlwaysOnTop = alwaysOnTop; }
00216         Format&     alwaysOnTop( bool top = true ) { mAlwaysOnTop = top; return *this; }
00218         void        enableFullScreenButton( bool enabled = true ) { mFullScreenButtonEnabled = enabled; }
00220         Format&     fullScreenButton( bool enabled = true ) { mFullScreenButtonEnabled = enabled; return *this; }
00222         bool        isFullScreenButtonEnabled() const { return mFullScreenButtonEnabled; }
00223 
00225         std::string getTitle() const { return mTitle; }
00227         void        setTitle( const std::string &title ) { mTitle = title; }
00229         Format&     title( const std::string &t ) { mTitle = t; return *this; }
00230 
00231       private:
00232         RendererRef             mRenderer;
00233         bool                    mFullScreen;
00234         FullScreenOptions       mFullScreenOptions;
00235         DisplayRef              mDisplay;
00236         Vec2i                   mSize, mPos;
00237         bool                    mPosSpecified;
00238         bool                    mResizable, mBorderless, mAlwaysOnTop, mFullScreenButtonEnabled;
00239         std::string             mTitle;
00240 
00241 #if defined( CINDER_COCOA_TOUCH )
00242         UIViewController *mRootViewController;
00243 #endif
00244     };
00245 
00247     bool    isFullScreen() const;
00249     void    setFullScreen( bool fullScreen = true, const FullScreenOptions& options = FullScreenOptions() );
00251     int32_t getWidth() const { return getSize().x; }
00253     int32_t getHeight() const { return getSize().y; }
00255     float   getAspectRatio() const { return getSize().x / (float)getSize().y; }
00257     Area    getBounds() const { return Area( 0, 0, getSize().x, getSize().y ); }
00259     virtual Vec2i   getSize() const;
00261     void    setSize( int32_t width, int32_t height ) { setSize( Vec2i( width, height ) ); }
00263     void    setSize( const Vec2i &size );
00265     Vec2i   getPos() const;
00267     void    setPos( int32_t x, int32_t y ) const { setPos( Vec2i( x, y ) ); }
00269     void    setPos( const Vec2i &pos ) const;
00271     Vec2f   getCenter() const { return Vec2f( getWidth() / 2.0f, getHeight() / 2.0f ); }
00273     void    spanAllDisplays();
00274     
00276     float   getContentScale() const;
00278     float   toPixels( float s ) const { return s * getContentScale(); }
00280     Vec2f   toPixels( Vec2f s ) const { return s * getContentScale(); }
00282     Vec2i   toPixels( Vec2i s ) const { return Vec2i( (int32_t)(s.x * getContentScale()), (int32_t)(s.y * getContentScale()) ); }   
00284     Area    toPixels( const Area &a ) const { const float s = getContentScale(); return Area( (int32_t)(a.x1 * s), (int32_t)(a.y1 * s), (int32_t)(a.x2 * s), (int32_t)(a.y2 * s) ); }
00286     Rectf   toPixels( const Rectf &a ) const { return a * getContentScale(); }
00288     float   toPoints( float s ) const { return s / getContentScale(); }
00290     Vec2f   toPoints( Vec2f s ) const { return s / getContentScale(); }
00292     Vec2i   toPoints( Vec2i s ) const { return Vec2i( (int32_t)(s.x / getContentScale()), (int32_t)(s.y / getContentScale()) ); }   
00294     Area    toPoints( const Area &a ) const { const float s = 1.0f / getContentScale(); return Area( (int32_t)(a.x1 * s), (int32_t)(a.y1 * s), (int32_t)(a.x2 * s), (int32_t)(a.y2 * s) ); }
00296     Rectf   toPoints( const Rectf &a ) const { return a / getContentScale(); }
00297     
00299     std::string     getTitle() const;
00301     void            setTitle( const std::string &title );
00302     
00304     bool    isBorderless() const;
00306     void    setBorderless( bool borderless = true );
00308     bool    isAlwaysOnTop() const;
00310     void    setAlwaysOnTop( bool alwaysOnTop = true );
00311 
00313     void    hide();
00315     void    show();
00317     bool    isHidden() const;
00318 
00320     void    close();
00321 
00323     DisplayRef      getDisplay() const;
00325     RendererRef     getRenderer() const;
00327     void*           getNative() const;
00328 #if defined( CINDER_COCOA_TOUCH )
00329 
00330     UIViewController* getNativeViewController();
00331 #endif
00332 #if defined( CINDER_MSW )
00333 
00334     HDC             getDc() const { return getRenderer()->getDc(); }
00335 #endif
00336 
00337     EventSignalMouse&   getSignalMouseDown() { return mSignalMouseDown; }
00338     void                emitMouseDown( MouseEvent *event );
00339     template<typename T, typename Y>
00340     signals::connection connectMouseDown( T fn, Y *inst ) { return getSignalMouseDown().connect( std::bind( fn, inst, std::_1 ) ); }
00341 
00342     EventSignalMouse&   getSignalMouseDrag() { return mSignalMouseDrag; }
00343     void                emitMouseDrag( MouseEvent *event );
00344     template<typename T, typename Y>
00345     signals::connection connectMouseDrag( T fn, Y *inst ) { return getSignalMouseDrag().connect( std::bind( fn, inst, std::_1 ) ); }
00346 
00347     EventSignalMouse&   getSignalMouseUp() { return mSignalMouseUp; }
00348     void                emitMouseUp( MouseEvent *event );
00349     template<typename T, typename Y>
00350     signals::connection connectMouseUp( T fn, Y *inst ) { return getSignalMouseUp().connect( std::bind( fn, inst, std::_1 ) ); }
00351 
00352     EventSignalMouse&   getSignalMouseMove() { return mSignalMouseMove; }
00353     void                emitMouseMove( MouseEvent *event );
00354     template<typename T, typename Y>
00355     signals::connection connectMouseMove( T fn, Y *inst ) { return getSignalMouseMove().connect( std::bind( fn, inst, std::_1 ) ); }
00356 
00357     EventSignalMouse&   getSignalMouseWheel() { return mSignalMouseWheel; }
00358     void                emitMouseWheel( MouseEvent *event );
00359     template<typename T, typename Y>
00360     signals::connection connectMouseWheel( T fn, Y *inst ) { return getSignalMouseWheel().connect( std::bind( fn, inst, std::_1 ) ); }
00361 
00362     EventSignalTouch&   getSignalTouchesBegan() { return mSignalTouchesBegan; }
00363     void                emitTouchesBegan( TouchEvent *event );
00364     template<typename T, typename Y>
00365     signals::connection connectTouchesBegan( T fn, Y *inst ) { return getSignalTouchesBegan().connect( std::bind( fn, inst, std::_1 ) ); }
00366 
00367     EventSignalTouch&   getSignalTouchesMoved() { return mSignalTouchesMoved; }
00368     void                emitTouchesMoved( TouchEvent *event );
00369     template<typename T, typename Y>
00370     signals::connection connectTouchesMoved( T fn, Y *inst ) { return getSignalTouchesMoved().connect( std::bind( fn, inst, std::_1 ) ); }
00371 
00372     EventSignalTouch&   getSignalTouchesEnded() { return mSignalTouchesEnded; }
00373     void                emitTouchesEnded( TouchEvent *event );
00374     template<typename T, typename Y>
00375     signals::connection connectTouchesEnded( T fn, Y *inst ) { return getSignalTouchesEnded().connect( std::bind( fn, inst, std::_1 ) ); }
00376 
00378     const std::vector<TouchEvent::Touch>&   getActiveTouches() const;
00379 
00380     EventSignalKey&     getSignalKeyDown() { return mSignalKeyDown; }
00381     void                emitKeyDown( KeyEvent *event );
00382     template<typename T, typename Y>
00383     signals::connection connectKeyDown( T fn, Y *inst ) { return getSignalKeyDown().connect( std::bind( fn, inst, std::_1 ) ); }
00384 
00385     EventSignalKey&     getSignalKeyUp() { return mSignalKeyUp; }
00386     void                emitKeyUp( KeyEvent *event );
00387     template<typename T, typename Y>
00388     signals::connection connectKeyUp( T fn, Y *inst ) { return getSignalKeyUp().connect( std::bind( fn, inst, std::_1 ) ); }
00389     
00390     EventSignalWindow&  getSignalDraw() { return mSignalDraw; }
00392     void                emitDraw();
00393     template<typename T, typename Y>
00394     signals::connection connectDraw( T fn, Y *inst ) { return getSignalDraw().connect( std::bind( fn, inst ) ); }
00395 
00397     EventSignalWindow&  getSignalPostDraw() { return mSignalPostDraw; }
00398     template<typename T, typename Y>
00399     signals::connection connectPostDraw( T fn, Y *inst ) { return getSignalPostDraw().connect( std::bind( fn, inst ) ); }
00400 
00401     EventSignalWindow&  getSignalMove() { return mSignalMove; }
00402     void                emitMove();
00403     template<typename T, typename Y>
00404     signals::connection connectMove( T fn, Y *inst ) { return getSignalMove().connect( std::bind( fn, inst ) ); }
00405 
00406     EventSignalWindow&  getSignalResize() { return mSignalResize; }
00407     void                emitResize();
00408     template<typename T, typename Y>
00409     signals::connection connectResize( T fn, Y *inst ) { return getSignalResize().connect( std::bind( fn, inst ) ); }
00410 
00411     EventSignalWindow&  getSignalDisplayChange() { return mSignalDisplayChange; }
00412     void                emitDisplayChange();
00413     template<typename T, typename Y>
00414     signals::connection connectDisplayChange( T fn, Y *inst ) { return getSignalDisplayChange().connect( std::bind( fn, inst ) ); }
00415 
00417     EventSignalWindow&  getSignalClose() { return mSignalClose; }
00419     void                emitClose();
00420     template<typename T, typename Y>
00421     signals::connection connectClose( T fn, Y *inst ) { return getSignalClose().connect( std::bind( fn, inst ) ); }
00422 
00423     EventSignalFileDrop&    getSignalFileDrop() { return mSignalFileDrop; }
00424     void                    emitFileDrop( FileDropEvent *event );
00425     template<typename T, typename Y>
00426     signals::connection     connectFileDrop( T fn, Y *inst ) { return getSignalFileDrop().connect( std::bind( fn, inst, std::_1 ) ); }
00427     
00429     template<typename T>
00430     T*          getUserData() { return static_cast<T*>( mUserData.get() ); }
00432     template<typename T>
00433     void        setUserData( T *userData ) { mUserData = std::shared_ptr<void>( std::shared_ptr<T>( userData ) ); }
00434     
00436     bool    isValid() const { return ! mValid; }
00437     void    setInvalid() { mValid = false; }
00438     
00440     // This should not be called except by App implementations
00441 #if defined( CINDER_COCOA ) && defined( __OBJC__ )
00442     static WindowRef        privateCreate__( id<WindowImplCocoa> impl, App *app )
00443 #elif defined( CINDER_MSW )
00444     static WindowRef        privateCreate__( WindowImplMsw *impl, App *app )
00445 #else
00446     static WindowRef        privateCreate__( WindowImplCocoa *impl, App *app )
00447 #endif
00448     {
00449         WindowRef result( new Window );
00450         result->setImpl( impl );
00451         result->setApp( app );
00452         
00453         return result;
00454     }
00456 
00457     App*            getApp() const { return mApp; }
00458     
00459   protected:
00460     Window() : mValid( true ), mImpl( 0 ) {}
00461   
00462     void    testValid() const {
00463         if( ! mValid )
00464             throw ExcInvalidWindow();
00465     }
00466 
00467     void        setApp( App *app ) { mApp = app; }  
00468 
00469 #if defined( CINDER_COCOA )
00470   #if defined( __OBJC__ )
00471     void        setImpl( id<WindowImplCocoa> impl ) { mImpl = impl; }
00472   #else
00473     void        setImpl( WindowImplCocoa *impl ) { mImpl = impl; }
00474   #endif
00475 #elif defined( CINDER_MSW )
00476     void        setImpl( WindowImplMsw *impl ) { mImpl = impl; }
00477 #endif
00478 
00479     App                         *mApp;
00480     bool                        mValid;
00481     std::shared_ptr<void>       mUserData;
00482     
00483     EventSignalMouse        mSignalMouseDown, mSignalMouseDrag, mSignalMouseUp, mSignalMouseWheel, mSignalMouseMove;
00484     EventSignalTouch        mSignalTouchesBegan, mSignalTouchesMoved, mSignalTouchesEnded;
00485     EventSignalKey          mSignalKeyDown, mSignalKeyUp;
00486     EventSignalWindow       mSignalDraw, mSignalPostDraw, mSignalMove, mSignalResize, mSignalDisplayChange, mSignalClose;
00487     EventSignalFileDrop     mSignalFileDrop;
00488     
00489 #if defined( CINDER_COCOA )
00490   #if defined( __OBJC__ )
00491     id<WindowImplCocoa>     mImpl;
00492   #else
00493     WindowImplCocoa         *mImpl; // necessary to trick c++ translation units
00494   #endif
00495 #elif defined( CINDER_MSW )
00496     WindowImplMsw       *mImpl;
00497 #endif
00498 };
00499 
00500 } } // namespace cinder::app