]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/camwindow.cpp
Merge commit 'c92c662abbbbc7ed93f628ad0e0f25e996ab686c' into garux-merge
[xonotic/netradiant.git] / radiant / camwindow.cpp
index 624b53fb0082d40ddfa89cca291126ee24915b66..a6134f5f08981cbc6c065b572d9d579a138154ae 100644 (file)
@@ -27,6 +27,9 @@
 
 #include "camwindow.h"
 
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
 #include "debugging/debugging.h"
 
 #include "iscenegraph.h"
@@ -90,7 +93,7 @@ struct camwindow_globals_private_t
                m_bCamDiscrete( true ),
                m_bCubicClipping( false ),
                m_showStats( true ),
-               m_nStrafeMode( 0 ){
+               m_nStrafeMode( 3 ){
        }
 
 };
@@ -142,6 +145,7 @@ struct camera_t
 
        bool m_strafe; // true when in strafemode toggled by the ctrl-key
        bool m_strafe_forward; // true when in strafemode by ctrl-key and shift is pressed for forward strafing
+       bool m_strafe_forward_invert; //silly option to invert forward strafing to support old fegs
 
        unsigned int movementflags; // movement flags
        Timer m_keycontrol_timer;
@@ -157,11 +161,11 @@ struct camera_t
        }
 
        View* m_view;
-       Callback m_update;
+       Callback<void()> m_update;
 
        static camera_draw_mode draw_mode;
 
-       camera_t( View* view, const Callback& update )
+       camera_t( View* view, const Callback<void()>& update )
                : width( 0 ),
                height( 0 ),
                timing( false ),
@@ -280,7 +284,7 @@ void Camera_FreeMove( camera_t& camera, int dx, int dy ){
 
                camera.origin -= camera.vright * strafespeed * dx;
                if ( camera.m_strafe_forward ) {
-                       camera.origin -= camera.vpn * strafespeed * dy;
+                       camera.origin += camera.m_strafe_forward_invert ? ( camera.vpn * strafespeed * dy ) : ( -camera.vpn * strafespeed * dy );
                }
                else{
                        camera.origin += camera.vup * strafespeed * dy;
@@ -319,17 +323,8 @@ void Camera_FreeMove( camera_t& camera, int dx, int dy ){
 }
 
 void Cam_MouseControl( camera_t& camera, int x, int y ){
-       int xl, xh;
-       int yl, yh;
-       float xf, yf;
-
-       xf = (float)( x - camera.width / 2 ) / ( camera.width / 2 );
-       yf = (float)( y - camera.height / 2 ) / ( camera.height / 2 );
-
-       xl = camera.width / 3;
-       xh = xl * 2;
-       yl = camera.height / 3;
-       yh = yl * 2;
+       float xf = (float)( x - camera.width / 2 ) / ( camera.width / 2 );
+       float yf = (float)( y - camera.height / 2 ) / ( camera.height / 2 );
 
        xf *= 1.0f - fabsf( yf );
        if ( xf < 0 ) {
@@ -370,7 +365,10 @@ const unsigned int MOVE_UP = 1 << 6;
 const unsigned int MOVE_DOWN = 1 << 7;
 const unsigned int MOVE_PITCHUP = 1 << 8;
 const unsigned int MOVE_PITCHDOWN = 1 << 9;
-const unsigned int MOVE_ALL = MOVE_FORWARD | MOVE_BACK | MOVE_ROTRIGHT | MOVE_ROTLEFT | MOVE_STRAFERIGHT | MOVE_STRAFELEFT | MOVE_UP | MOVE_DOWN | MOVE_PITCHUP | MOVE_PITCHDOWN;
+const unsigned int MOVE_FOCUS = 1 << 10;
+const unsigned int MOVE_ALL = MOVE_FORWARD | MOVE_BACK | MOVE_ROTRIGHT | MOVE_ROTLEFT | MOVE_STRAFERIGHT | MOVE_STRAFELEFT | MOVE_UP | MOVE_DOWN | MOVE_PITCHUP | MOVE_PITCHDOWN | MOVE_FOCUS;
+
+Vector3 Camera_getFocusPos( camera_t& camera );
 
 void Cam_KeyControl( camera_t& camera, float dtime ){
        // Update angles
@@ -415,6 +413,9 @@ void Cam_KeyControl( camera_t& camera, float dtime ){
        if ( camera.movementflags & MOVE_DOWN ) {
                vector3_add( camera.origin, vector3_scaled( g_vector3_axis_z, -dtime * g_camwindow_globals_private.m_nMoveSpeed ) );
        }
+       if ( camera.movementflags & MOVE_FOCUS ) {
+               camera.origin = Camera_getFocusPos( camera );
+       }
 
        Camera_updateModelview( camera );
 }
@@ -518,26 +519,34 @@ void Camera_PitchDown_KeyUp( camera_t& camera ){
        Camera_clearMovementFlags( camera, MOVE_PITCHDOWN );
 }
 
+void Camera_Focus_KeyDown( camera_t& camera ){
+       Camera_setMovementFlags( camera, MOVE_FOCUS );
+}
+void Camera_Focus_KeyUp( camera_t& camera ){
+       Camera_clearMovementFlags( camera, MOVE_FOCUS );
+}
 
-typedef ReferenceCaller<camera_t, &Camera_MoveForward_KeyDown> FreeMoveCameraMoveForwardKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveForward_KeyUp> FreeMoveCameraMoveForwardKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveBack_KeyDown> FreeMoveCameraMoveBackKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveBack_KeyUp> FreeMoveCameraMoveBackKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveLeft_KeyDown> FreeMoveCameraMoveLeftKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveLeft_KeyUp> FreeMoveCameraMoveLeftKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveRight_KeyDown> FreeMoveCameraMoveRightKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveRight_KeyUp> FreeMoveCameraMoveRightKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveUp_KeyDown> FreeMoveCameraMoveUpKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveUp_KeyUp> FreeMoveCameraMoveUpKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveDown_KeyDown> FreeMoveCameraMoveDownKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveDown_KeyUp> FreeMoveCameraMoveDownKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyDown> FreeMoveCameraMoveForwardKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyUp> FreeMoveCameraMoveForwardKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveBack_KeyDown> FreeMoveCameraMoveBackKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveBack_KeyUp> FreeMoveCameraMoveBackKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveLeft_KeyDown> FreeMoveCameraMoveLeftKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveLeft_KeyUp> FreeMoveCameraMoveLeftKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveRight_KeyDown> FreeMoveCameraMoveRightKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveRight_KeyUp> FreeMoveCameraMoveRightKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveUp_KeyDown> FreeMoveCameraMoveUpKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveUp_KeyUp> FreeMoveCameraMoveUpKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyDown> FreeMoveCameraMoveDownKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyUp> FreeMoveCameraMoveDownKeyUpCaller;
 
+typedef ReferenceCaller<camera_t, void(), &Camera_Focus_KeyDown> FreeMoveCameraFocusKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_Focus_KeyUp> FreeMoveCameraFocusKeyUpCaller;
 
-#define SPEED_MOVE 32
-#define SPEED_TURN 22.5
-#define MIN_CAM_SPEED 10
-#define MAX_CAM_SPEED 610
-#define CAM_SPEED_STEP 50
+const float SPEED_MOVE = 32;
+const float SPEED_TURN = 22.5;
+const float MIN_CAM_SPEED = 10;
+const float MAX_CAM_SPEED = 610;
+const float CAM_SPEED_STEP = 50;
 
 void Camera_MoveForward_Discrete( camera_t& camera ){
        Camera_Move_updateAxes( camera );
@@ -601,9 +610,9 @@ class RadiantCameraView : public CameraView
 {
 camera_t& m_camera;
 View* m_view;
-Callback m_update;
+Callback<void()> m_update;
 public:
-RadiantCameraView( camera_t& camera, View* view, const Callback& update ) : m_camera( camera ), m_view( view ), m_update( update ){
+RadiantCameraView( camera_t& camera, View* view, const Callback<void()>& update ) : m_camera( camera ), m_view( view ), m_update( update ){
 }
 void update(){
        m_view->Construct( m_camera.projection, m_camera.modelview, m_camera.width, m_camera.height );
@@ -629,16 +638,12 @@ void Camera_motionDelta( int x, int y, unsigned int state, void* data ){
 
        cam->m_mouseMove.motion_delta( x, y, state );
 
+       cam->m_strafe_forward_invert = false;
+
        switch ( g_camwindow_globals_private.m_nStrafeMode )
        {
        case 0:
-               cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0;
-               if ( cam->m_strafe ) {
-                       cam->m_strafe_forward = ( state & GDK_SHIFT_MASK ) != 0;
-               }
-               else{
-                       cam->m_strafe_forward = false;
-               }
+               cam->m_strafe = false;
                break;
        case 1:
                cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0 && ( state & GDK_SHIFT_MASK ) == 0;
@@ -648,9 +653,24 @@ void Camera_motionDelta( int x, int y, unsigned int state, void* data ){
                cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0 && ( state & GDK_SHIFT_MASK ) == 0;
                cam->m_strafe_forward = cam->m_strafe;
                break;
+       case 4:
+               cam->m_strafe_forward_invert = true;
+       default:
+               cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0;
+               if ( cam->m_strafe ) {
+                       cam->m_strafe_forward = ( state & GDK_SHIFT_MASK ) != 0;
+               }
+               else{
+                       cam->m_strafe_forward = false;
+               }
+               break;
        }
 }
 
+
+
+
+
 class CamWnd
 {
 View m_view;
@@ -669,8 +689,8 @@ static Shader* m_state_select2;
 FreezePointer m_freezePointer;
 
 public:
-GtkWidget* m_gl_widget;
-GtkWindow* m_parent;
+ui::GLArea m_gl_widget;
+ui::Window m_parent{ui::null};
 
 SelectionSystemWindowObserver* m_window_observer;
 XORRectangle m_XORRectangle;
@@ -712,7 +732,7 @@ static void releaseStates(){
 
 camera_t& getCamera(){
        return m_Camera;
-};
+}
 
 void BenchMark();
 void Cam_ChangeFloor( bool up );
@@ -729,7 +749,7 @@ private:
 void Cam_Draw();
 };
 
-typedef MemberCaller<CamWnd, &CamWnd::queue_draw> CamWndQueueDraw;
+typedef MemberCaller<CamWnd, void(), &CamWnd::queue_draw> CamWndQueueDraw;
 
 Shader* CamWnd::m_state_select1 = 0;
 Shader* CamWnd::m_state_select2 = 0;
@@ -756,19 +776,19 @@ void GlobalCamera_setCamWnd( CamWnd& camwnd ){
 }
 
 
-GtkWidget* CamWnd_getWidget( CamWnd& camwnd ){
+ui::GLArea CamWnd_getWidget( CamWnd& camwnd ){
        return camwnd.m_gl_widget;
 }
 
-GtkWindow* CamWnd_getParent( CamWnd& camwnd ){
+ui::Window CamWnd_getParent( CamWnd& camwnd ){
        return camwnd.m_parent;
 }
 
 ToggleShown g_camera_shown( true );
 
-void CamWnd_setParent( CamWnd& camwnd, GtkWindow* parent ){
+void CamWnd_setParent( CamWnd& camwnd, ui::Window parent ){
        camwnd.m_parent = parent;
-       g_camera_shown.connect( GTK_WIDGET( camwnd.m_parent ) );
+       g_camera_shown.connect( camwnd.m_parent );
 }
 
 void CamWnd_Update( CamWnd& camwnd ){
@@ -799,7 +819,7 @@ void Camera_setAngles( CamWnd& camwnd, const Vector3& angles ){
 // =============================================================================
 // CamWnd class
 
-gboolean enable_freelook_button_press( GtkWidget* widget, GdkEventButton* event, CamWnd* camwnd ){
+gboolean enable_freelook_button_press( ui::Widget widget, GdkEventButton* event, CamWnd* camwnd ){
        if ( event->type == GDK_BUTTON_PRESS && event->button == 3 && modifiers_for_state( event->state ) == c_modifierNone ) {
                camwnd->EnableFreeMove();
                return TRUE;
@@ -807,7 +827,7 @@ gboolean enable_freelook_button_press( GtkWidget* widget, GdkEventButton* event,
        return FALSE;
 }
 
-gboolean disable_freelook_button_press( GtkWidget* widget, GdkEventButton* event, CamWnd* camwnd ){
+gboolean disable_freelook_button_press( ui::Widget widget, GdkEventButton* event, CamWnd* camwnd ){
        if ( event->type == GDK_BUTTON_PRESS && event->button == 3 && modifiers_for_state( event->state ) == c_modifierNone ) {
                camwnd->DisableFreeMove();
                return TRUE;
@@ -816,7 +836,7 @@ gboolean disable_freelook_button_press( GtkWidget* widget, GdkEventButton* event
 }
 
 #if 0
-gboolean mousecontrol_button_press( GtkWidget* widget, GdkEventButton* event, CamWnd* camwnd ){
+gboolean mousecontrol_button_press( ui::Widget widget, GdkEventButton* event, CamWnd* camwnd ){
        if ( event->type == GDK_BUTTON_PRESS && event->button == 3 ) {
                Cam_MouseControl( camwnd->getCamera(), event->x, widget->allocation.height - 1 - event->y );
        }
@@ -825,20 +845,21 @@ gboolean mousecontrol_button_press( GtkWidget* widget, GdkEventButton* event, Ca
 #endif
 
 void camwnd_update_xor_rectangle( CamWnd& self, rect_t area ){
-       if ( GTK_WIDGET_VISIBLE( self.m_gl_widget ) ) {
+       if ( self.m_gl_widget.visible() ) {
                self.m_XORRectangle.set( rectangle_from_area( area.min, area.max, self.getCamera().width, self.getCamera().height ) );
        }
 }
 
 
-gboolean selection_button_press( GtkWidget* widget, GdkEventButton* event, WindowObserver* observer ){
+gboolean selection_button_press( ui::Widget widget, GdkEventButton* event, WindowObserver* observer ){
        if ( event->type == GDK_BUTTON_PRESS ) {
+               gtk_widget_grab_focus( widget );
                observer->onMouseDown( WindowVector_forDouble( event->x, event->y ), button_for_button( event->button ), modifiers_for_state( event->state ) );
        }
        return FALSE;
 }
 
-gboolean selection_button_release( GtkWidget* widget, GdkEventButton* event, WindowObserver* observer ){
+gboolean selection_button_release( ui::Widget widget, GdkEventButton* event, WindowObserver* observer ){
        if ( event->type == GDK_BUTTON_RELEASE ) {
                observer->onMouseUp( WindowVector_forDouble( event->x, event->y ), button_for_button( event->button ), modifiers_for_state( event->state ) );
        }
@@ -850,33 +871,64 @@ void selection_motion( gdouble x, gdouble y, guint state, void* data ){
        reinterpret_cast<WindowObserver*>( data )->onMouseMotion( WindowVector_forDouble( x, y ), modifiers_for_state( state ) );
 }
 
-inline WindowVector windowvector_for_widget_centre( GtkWidget* widget ){
-       return WindowVector( static_cast<float>( widget->allocation.width / 2 ), static_cast<float>( widget->allocation.height / 2 ) );
+inline WindowVector windowvector_for_widget_centre( ui::Widget widget ){
+       auto allocation = widget.dimensions();
+       return WindowVector( static_cast<float>( allocation.width / 2 ), static_cast<float>(allocation.height / 2 ) );
 }
 
-gboolean selection_button_press_freemove( GtkWidget* widget, GdkEventButton* event, WindowObserver* observer ){
+gboolean selection_button_press_freemove( ui::Widget widget, GdkEventButton* event, WindowObserver* observer ){
        if ( event->type == GDK_BUTTON_PRESS ) {
                observer->onMouseDown( windowvector_for_widget_centre( widget ), button_for_button( event->button ), modifiers_for_state( event->state ) );
        }
        return FALSE;
 }
 
-gboolean selection_button_release_freemove( GtkWidget* widget, GdkEventButton* event, WindowObserver* observer ){
+gboolean selection_button_release_freemove( ui::Widget widget, GdkEventButton* event, WindowObserver* observer ){
        if ( event->type == GDK_BUTTON_RELEASE ) {
                observer->onMouseUp( windowvector_for_widget_centre( widget ), button_for_button( event->button ), modifiers_for_state( event->state ) );
        }
        return FALSE;
 }
 
-gboolean selection_motion_freemove( GtkWidget *widget, GdkEventMotion *event, WindowObserver* observer ){
+gboolean selection_motion_freemove( ui::Widget widget, GdkEventMotion *event, WindowObserver* observer ){
        observer->onMouseMotion( windowvector_for_widget_centre( widget ), modifiers_for_state( event->state ) );
        return FALSE;
 }
 
-gboolean wheelmove_scroll( GtkWidget* widget, GdkEventScroll* event, CamWnd* camwnd ){
+gboolean wheelmove_scroll( ui::Widget widget, GdkEventScroll* event, CamWnd* camwnd ){
+       //gtk_window_set_focus( camwnd->m_parent, camwnd->m_gl_widget );
+       gtk_widget_grab_focus( camwnd->m_gl_widget );
+       if( !gtk_window_is_active( camwnd->m_parent ) )
+               gtk_window_present( camwnd->m_parent );
+
        if ( event->direction == GDK_SCROLL_UP ) {
                Camera_Freemove_updateAxes( camwnd->getCamera() );
-               Camera_setOrigin( *camwnd, vector3_added( Camera_getOrigin( *camwnd ), vector3_scaled( camwnd->getCamera().forward, static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ) ) ) );
+               if( camwnd->m_bFreeMove || !g_camwindow_globals.m_bZoomInToPointer ){
+                       Camera_setOrigin( *camwnd, vector3_added( Camera_getOrigin( *camwnd ), vector3_scaled( camwnd->getCamera().forward, static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ) ) ) );
+               }
+               else{
+                       //Matrix4 maa = matrix4_multiplied_by_matrix4( camwnd->getCamera().projection, camwnd->getCamera().modelview );
+                       Matrix4 maa = camwnd->getCamera().m_view->GetViewMatrix();
+                       matrix4_affine_invert( maa );
+
+                       float x = static_cast<float>( event->x );
+                       float y = static_cast<float>( event->y );
+                       Vector3 normalized;
+
+                       normalized[0] = 2.0f * ( x ) / static_cast<float>( camwnd->getCamera().width ) - 1.0f;
+                       normalized[1] = 2.0f * ( y )/ static_cast<float>( camwnd->getCamera().height ) - 1.0f;
+                       normalized[1] *= -1.f;
+                       normalized[2] = 0.f;
+
+                       normalized *= 16.0f;
+                               //globalOutputStream() << normalized << " normalized    ";
+                       matrix4_transform_point( maa, normalized );
+                               //globalOutputStream() << normalized << "\n";
+                       Vector3 norm = vector3_normalised( normalized - Camera_getOrigin( *camwnd ) );
+                               //globalOutputStream() << normalized - Camera_getOrigin( *camwnd ) << "  normalized - Camera_getOrigin( *camwnd )\n";
+                               //globalOutputStream() << norm << "  norm\n";
+                       Camera_setOrigin( *camwnd, vector3_added( Camera_getOrigin( *camwnd ), vector3_scaled( norm, static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ) ) ) );
+               }
        }
        else if ( event->direction == GDK_SCROLL_DOWN ) {
                Camera_Freemove_updateAxes( camwnd->getCamera() );
@@ -886,7 +938,7 @@ gboolean wheelmove_scroll( GtkWidget* widget, GdkEventScroll* event, CamWnd* cam
        return FALSE;
 }
 
-gboolean camera_size_allocate( GtkWidget* widget, GtkAllocation* allocation, CamWnd* camwnd ){
+gboolean camera_size_allocate( ui::Widget widget, GtkAllocation* allocation, CamWnd* camwnd ){
        camwnd->getCamera().width = allocation->width;
        camwnd->getCamera().height = allocation->height;
        Camera_updateProjection( camwnd->getCamera() );
@@ -895,7 +947,7 @@ gboolean camera_size_allocate( GtkWidget* widget, GtkAllocation* allocation, Cam
        return FALSE;
 }
 
-gboolean camera_expose( GtkWidget* widget, GdkEventExpose* event, gpointer data ){
+gboolean camera_expose( ui::Widget widget, GdkEventExpose* event, gpointer data ){
        reinterpret_cast<CamWnd*>( data )->draw();
        return FALSE;
 }
@@ -913,101 +965,107 @@ void KeyEvent_disconnect( const char* name ){
 }
 
 void CamWnd_registerCommands( CamWnd& camwnd ){
-       GlobalKeyEvents_insert( "CameraForward", Accelerator( GDK_Up ),
-                                                       ReferenceCaller<camera_t, Camera_MoveForward_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveForward_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraForward", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveForward_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveForward_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraBack", Accelerator( GDK_Down ),
-                                                       ReferenceCaller<camera_t, Camera_MoveBack_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveBack_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraBack", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveBack_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveBack_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraLeft", Accelerator( GDK_Left ),
-                                                       ReferenceCaller<camera_t, Camera_RotateLeft_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_RotateLeft_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraLeft", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateLeft_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateLeft_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraRight", Accelerator( GDK_Right ),
-                                                       ReferenceCaller<camera_t, Camera_RotateRight_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_RotateRight_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraRight", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateRight_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateRight_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraStrafeRight", Accelerator( GDK_period ),
-                                                       ReferenceCaller<camera_t, Camera_MoveRight_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveRight_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraStrafeRight", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveRight_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveRight_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraStrafeLeft", Accelerator( GDK_comma ),
-                                                       ReferenceCaller<camera_t, Camera_MoveLeft_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveLeft_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraStrafeLeft", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveLeft_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveLeft_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraUp", Accelerator( 'D' ),
-                                                       ReferenceCaller<camera_t, Camera_MoveUp_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveUp_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraUp", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveUp_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveUp_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraDown", Accelerator( 'C' ),
-                                                       ReferenceCaller<camera_t, Camera_MoveDown_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveDown_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraDown", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveDown_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveDown_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraAngleDown", Accelerator( 'A' ),
-                                                       ReferenceCaller<camera_t, Camera_PitchDown_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_PitchDown_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraAngleUp", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchUp_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchUp_KeyUp>( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraAngleUp", Accelerator( 'Z' ),
-                                                       ReferenceCaller<camera_t, Camera_PitchUp_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_PitchUp_KeyUp>( camwnd.getCamera() )
+       GlobalKeyEvents_insert( "CameraAngleDown", accelerator_null(),
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchDown_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchDown_KeyUp>( camwnd.getCamera() )
                                                        );
 
-       GlobalKeyEvents_insert( "CameraFreeMoveForward", Accelerator( 'W' ),
+
+       GlobalKeyEvents_insert( "CameraFreeMoveForward", accelerator_null(),
                                                        FreeMoveCameraMoveForwardKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveForwardKeyUpCaller( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraFreeMoveBack", Accelerator( 'S' ),
+       GlobalKeyEvents_insert( "CameraFreeMoveBack", accelerator_null(),
                                                        FreeMoveCameraMoveBackKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveBackKeyUpCaller( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraFreeMoveLeft", Accelerator( 'A' ),
+       GlobalKeyEvents_insert( "CameraFreeMoveLeft", accelerator_null(),
                                                        FreeMoveCameraMoveLeftKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveLeftKeyUpCaller( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraFreeMoveRight", Accelerator( 'D' ),
+       GlobalKeyEvents_insert( "CameraFreeMoveRight", accelerator_null(),
                                                        FreeMoveCameraMoveRightKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveRightKeyUpCaller( camwnd.getCamera() )
                                                        );
 
-       GlobalKeyEvents_insert( "CameraFreeMoveForward2", Accelerator( GDK_Up ),
+       GlobalKeyEvents_insert( "CameraFreeMoveForward2", accelerator_null(),
                                                        FreeMoveCameraMoveForwardKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveForwardKeyUpCaller( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraFreeMoveBack2", Accelerator( GDK_Down ),
+       GlobalKeyEvents_insert( "CameraFreeMoveBack2", accelerator_null(),
                                                        FreeMoveCameraMoveBackKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveBackKeyUpCaller( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraFreeMoveLeft2", Accelerator( GDK_Left ),
+       GlobalKeyEvents_insert( "CameraFreeMoveLeft2", accelerator_null(),
                                                        FreeMoveCameraMoveLeftKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveLeftKeyUpCaller( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraFreeMoveRight2", Accelerator( GDK_Right ),
+       GlobalKeyEvents_insert( "CameraFreeMoveRight2", accelerator_null(),
                                                        FreeMoveCameraMoveRightKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveRightKeyUpCaller( camwnd.getCamera() )
                                                        );
 
-       GlobalKeyEvents_insert( "CameraFreeMoveUp", Accelerator( GDK_period ),
+       GlobalKeyEvents_insert( "CameraFreeMoveUp", accelerator_null(),
                                                        FreeMoveCameraMoveUpKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveUpKeyUpCaller( camwnd.getCamera() )
                                                        );
-       GlobalKeyEvents_insert( "CameraFreeMoveDown", Accelerator( GDK_comma ),
+       GlobalKeyEvents_insert( "CameraFreeMoveDown", accelerator_null(),
                                                        FreeMoveCameraMoveDownKeyDownCaller( camwnd.getCamera() ),
                                                        FreeMoveCameraMoveDownKeyUpCaller( camwnd.getCamera() )
                                                        );
 
-       GlobalCommands_insert( "CameraForward", ReferenceCaller<camera_t, Camera_MoveForward_Discrete>( camwnd.getCamera() ), Accelerator( GDK_Up ) );
-       GlobalCommands_insert( "CameraBack", ReferenceCaller<camera_t, Camera_MoveBack_Discrete>( camwnd.getCamera() ), Accelerator( GDK_Down ) );
-       GlobalCommands_insert( "CameraLeft", ReferenceCaller<camera_t, Camera_RotateLeft_Discrete>( camwnd.getCamera() ), Accelerator( GDK_Left ) );
-       GlobalCommands_insert( "CameraRight", ReferenceCaller<camera_t, Camera_RotateRight_Discrete>( camwnd.getCamera() ), Accelerator( GDK_Right ) );
-       GlobalCommands_insert( "CameraStrafeRight", ReferenceCaller<camera_t, Camera_MoveRight_Discrete>( camwnd.getCamera() ), Accelerator( GDK_period ) );
-       GlobalCommands_insert( "CameraStrafeLeft", ReferenceCaller<camera_t, Camera_MoveLeft_Discrete>( camwnd.getCamera() ), Accelerator( GDK_comma ) );
+       GlobalKeyEvents_insert( "CameraFreeFocus", accelerator_null(),
+                                                       FreeMoveCameraFocusKeyDownCaller( camwnd.getCamera() ),
+                                                       FreeMoveCameraFocusKeyUpCaller( camwnd.getCamera() )
+                                                       );
+
+       GlobalCommands_insert( "CameraForward", ReferenceCaller<camera_t, void(), Camera_MoveForward_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraBack", ReferenceCaller<camera_t, void(), Camera_MoveBack_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraLeft", ReferenceCaller<camera_t, void(), Camera_RotateLeft_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraRight", ReferenceCaller<camera_t, void(), Camera_RotateRight_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraStrafeRight", ReferenceCaller<camera_t, void(), Camera_MoveRight_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraStrafeLeft", ReferenceCaller<camera_t, void(), Camera_MoveLeft_Discrete>( camwnd.getCamera() ) );
 
-       GlobalCommands_insert( "CameraUp", ReferenceCaller<camera_t, Camera_MoveUp_Discrete>( camwnd.getCamera() ), Accelerator( 'D' ) );
-       GlobalCommands_insert( "CameraDown", ReferenceCaller<camera_t, Camera_MoveDown_Discrete>( camwnd.getCamera() ), Accelerator( 'C' ) );
-       GlobalCommands_insert( "CameraAngleUp", ReferenceCaller<camera_t, Camera_PitchUp_Discrete>( camwnd.getCamera() ), Accelerator( 'A' ) );
-       GlobalCommands_insert( "CameraAngleDown", ReferenceCaller<camera_t, Camera_PitchDown_Discrete>( camwnd.getCamera() ), Accelerator( 'Z' ) );
+       GlobalCommands_insert( "CameraUp", ReferenceCaller<camera_t, void(), Camera_MoveUp_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraDown", ReferenceCaller<camera_t, void(), Camera_MoveDown_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraAngleUp", ReferenceCaller<camera_t, void(), Camera_PitchUp_Discrete>( camwnd.getCamera() ) );
+       GlobalCommands_insert( "CameraAngleDown", ReferenceCaller<camera_t, void(), Camera_PitchDown_Discrete>( camwnd.getCamera() ) );
 }
 
 void CamWnd_Move_Enable( CamWnd& camwnd ){
@@ -1062,12 +1120,23 @@ void CamWnd_Move_Discrete_Disable( CamWnd& camwnd ){
        command_disconnect_accelerator( "CameraAngleDown" );
 }
 
-void CamWnd_Move_Discrete_Import( CamWnd& camwnd, bool value ){
+struct CamWnd_Move_Discrete {
+       static void Export(const Callback<void(bool)> &returnz) {
+               returnz(g_camwindow_globals_private.m_bCamDiscrete);
+       }
+
+       static void Import(bool value) {
+               if (g_camwnd) {
+                       Import_(*g_camwnd, value);
+               } else {
+                       g_camwindow_globals_private.m_bCamDiscrete = value;
+               }
+       }
+
+       static void Import_(CamWnd &camwnd, bool value) {
        if ( g_camwindow_globals_private.m_bCamDiscrete ) {
                CamWnd_Move_Discrete_Disable( camwnd );
-       }
-       else
-       {
+               } else {
                CamWnd_Move_Disable( camwnd );
        }
 
@@ -1075,31 +1144,19 @@ void CamWnd_Move_Discrete_Import( CamWnd& camwnd, bool value ){
 
        if ( g_camwindow_globals_private.m_bCamDiscrete ) {
                CamWnd_Move_Discrete_Enable( camwnd );
-       }
-       else
-       {
+               } else {
                CamWnd_Move_Enable( camwnd );
        }
 }
-
-void CamWnd_Move_Discrete_Import( bool value ){
-       if ( g_camwnd != 0 ) {
-               CamWnd_Move_Discrete_Import( *g_camwnd, value );
-       }
-       else
-       {
-               g_camwindow_globals_private.m_bCamDiscrete = value;
-       }
-}
-
+};
 
 
 void CamWnd_Add_Handlers_Move( CamWnd& camwnd ){
-       camwnd.m_selection_button_press_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "button_press_event", G_CALLBACK( selection_button_press ), camwnd.m_window_observer );
-       camwnd.m_selection_button_release_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "button_release_event", G_CALLBACK( selection_button_release ), camwnd.m_window_observer );
-       camwnd.m_selection_motion_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "motion_notify_event", G_CALLBACK( DeferredMotion::gtk_motion ), &camwnd.m_deferred_motion );
+       camwnd.m_selection_button_press_handler = camwnd.m_gl_widget.connect( "button_press_event", G_CALLBACK( selection_button_press ), camwnd.m_window_observer );
+       camwnd.m_selection_button_release_handler = camwnd.m_gl_widget.connect( "button_release_event", G_CALLBACK( selection_button_release ), camwnd.m_window_observer );
+       camwnd.m_selection_motion_handler = camwnd.m_gl_widget.connect( "motion_notify_event", G_CALLBACK( DeferredMotion::gtk_motion ), &camwnd.m_deferred_motion );
 
-       camwnd.m_freelook_button_press_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "button_press_event", G_CALLBACK( enable_freelook_button_press ), &camwnd );
+       camwnd.m_freelook_button_press_handler = camwnd.m_gl_widget.connect( "button_press_event", G_CALLBACK( enable_freelook_button_press ), &camwnd );
 
        if ( g_camwindow_globals_private.m_bCamDiscrete ) {
                CamWnd_Move_Discrete_Enable( camwnd );
@@ -1127,11 +1184,11 @@ void CamWnd_Remove_Handlers_Move( CamWnd& camwnd ){
 }
 
 void CamWnd_Add_Handlers_FreeMove( CamWnd& camwnd ){
-       camwnd.m_selection_button_press_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "button_press_event", G_CALLBACK( selection_button_press_freemove ), camwnd.m_window_observer );
-       camwnd.m_selection_button_release_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "button_release_event", G_CALLBACK( selection_button_release_freemove ), camwnd.m_window_observer );
-       camwnd.m_selection_motion_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "motion_notify_event", G_CALLBACK( selection_motion_freemove ), camwnd.m_window_observer );
+       camwnd.m_selection_button_press_handler = camwnd.m_gl_widget.connect( "button_press_event", G_CALLBACK( selection_button_press_freemove ), camwnd.m_window_observer );
+       camwnd.m_selection_button_release_handler = camwnd.m_gl_widget.connect( "button_release_event", G_CALLBACK( selection_button_release_freemove ), camwnd.m_window_observer );
+       camwnd.m_selection_motion_handler = camwnd.m_gl_widget.connect( "motion_notify_event", G_CALLBACK( selection_motion_freemove ), camwnd.m_window_observer );
 
-       camwnd.m_freelook_button_press_handler = g_signal_connect( G_OBJECT( camwnd.m_gl_widget ), "button_press_event", G_CALLBACK( disable_freelook_button_press ), &camwnd );
+       camwnd.m_freelook_button_press_handler = camwnd.m_gl_widget.connect( "button_press_event", G_CALLBACK( disable_freelook_button_press ), &camwnd );
 
        KeyEvent_connect( "CameraFreeMoveForward" );
        KeyEvent_connect( "CameraFreeMoveBack" );
@@ -1145,6 +1202,8 @@ void CamWnd_Add_Handlers_FreeMove( CamWnd& camwnd ){
 
        KeyEvent_connect( "CameraFreeMoveUp" );
        KeyEvent_connect( "CameraFreeMoveDown" );
+
+       KeyEvent_connect( "CameraFreeFocus" );
 }
 
 void CamWnd_Remove_Handlers_FreeMove( CamWnd& camwnd ){
@@ -1161,6 +1220,8 @@ void CamWnd_Remove_Handlers_FreeMove( CamWnd& camwnd ){
        KeyEvent_disconnect( "CameraFreeMoveUp" );
        KeyEvent_disconnect( "CameraFreeMoveDown" );
 
+       KeyEvent_disconnect( "CameraFreeFocus" );
+
        g_signal_handler_disconnect( G_OBJECT( camwnd.m_gl_widget ), camwnd.m_selection_button_press_handler );
        g_signal_handler_disconnect( G_OBJECT( camwnd.m_gl_widget ), camwnd.m_selection_button_release_handler );
        g_signal_handler_disconnect( G_OBJECT( camwnd.m_gl_widget ), camwnd.m_selection_motion_handler );
@@ -1171,11 +1232,11 @@ void CamWnd_Remove_Handlers_FreeMove( CamWnd& camwnd ){
 CamWnd::CamWnd() :
        m_view( true ),
        m_Camera( &m_view, CamWndQueueDraw( *this ) ),
-       m_cameraview( m_Camera, &m_view, ReferenceCaller<CamWnd, CamWnd_Update>( *this ) ),
+       m_cameraview( m_Camera, &m_view, ReferenceCaller<CamWnd, void(), CamWnd_Update>( *this ) ),
        m_gl_widget( glwidget_new( TRUE ) ),
        m_window_observer( NewWindowObserver() ),
        m_XORRectangle( m_gl_widget ),
-       m_deferredDraw( WidgetQueueDrawCaller( *m_gl_widget ) ),
+       m_deferredDraw( WidgetQueueDrawCaller( m_gl_widget ) ),
        m_deferred_motion( selection_motion, m_window_observer ),
        m_selection_button_press_handler( 0 ),
        m_selection_button_release_handler( 0 ),
@@ -1187,16 +1248,16 @@ CamWnd::CamWnd() :
        GlobalWindowObservers_add( m_window_observer );
        GlobalWindowObservers_connectWidget( m_gl_widget );
 
-       m_window_observer->setRectangleDrawCallback( ReferenceCaller1<CamWnd, rect_t, camwnd_update_xor_rectangle>( *this ) );
+       m_window_observer->setRectangleDrawCallback( ReferenceCaller<CamWnd, void(rect_t), camwnd_update_xor_rectangle>( *this ) );
        m_window_observer->setView( m_view );
 
-       gtk_widget_ref( m_gl_widget );
+       g_object_ref( m_gl_widget._handle );
 
        gtk_widget_set_events( m_gl_widget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK );
-       GTK_WIDGET_SET_FLAGS( m_gl_widget, GTK_CAN_FOCUS );
+       gtk_widget_set_can_focus( m_gl_widget, true );
 
-       m_sizeHandler = g_signal_connect( G_OBJECT( m_gl_widget ), "size_allocate", G_CALLBACK( camera_size_allocate ), this );
-       m_exposeHandler = g_signal_connect( G_OBJECT( m_gl_widget ), "expose_event", G_CALLBACK( camera_expose ), this );
+       m_sizeHandler = m_gl_widget.connect( "size_allocate", G_CALLBACK( camera_size_allocate ), this );
+       m_exposeHandler = m_gl_widget.on_render( G_CALLBACK( camera_expose ), this );
 
        Map_addValidCallback( g_map, DeferredDrawOnMapValidChangedCaller( m_deferredDraw ) );
 
@@ -1204,9 +1265,9 @@ CamWnd::CamWnd() :
 
        CamWnd_Add_Handlers_Move( *this );
 
-       g_signal_connect( G_OBJECT( m_gl_widget ), "scroll_event", G_CALLBACK( wheelmove_scroll ), this );
+       m_gl_widget.connect( "scroll_event", G_CALLBACK( wheelmove_scroll ), this );
 
-       AddSceneChangeCallback( ReferenceCaller<CamWnd, CamWnd_Update>( *this ) );
+       AddSceneChangeCallback( ReferenceCaller<CamWnd, void(), CamWnd_Update>( *this ) );
 
        PressedButtons_connect( g_pressedButtons, m_gl_widget );
 }
@@ -1221,7 +1282,7 @@ CamWnd::~CamWnd(){
        g_signal_handler_disconnect( G_OBJECT( m_gl_widget ), m_sizeHandler );
        g_signal_handler_disconnect( G_OBJECT( m_gl_widget ), m_exposeHandler );
 
-       gtk_widget_unref( m_gl_widget );
+       m_gl_widget.unref();
 
        m_window_observer->release();
 }
@@ -1293,7 +1354,7 @@ if ( ( m_bFreeMove && ( buttons == ( RAD_CONTROL | RAD_SHIFT ) ) )
 void CamWnd::Cam_PositionDrag(){
        int x, y;
 
-       Sys_GetCursorPos( GTK_WINDOW( m_gl_widget ), &x, &y );
+       Sys_GetCursorPos( m_gl_widget, &x, &y );
        if ( x != m_PositionDragCursorX || y != m_PositionDragCursorY ) {
                x -= m_PositionDragCursorX;
                vector3_add( m_Camera.origin, vector3_scaled( m_Camera.vright, x ) );
@@ -1303,7 +1364,7 @@ void CamWnd::Cam_PositionDrag(){
                CamWnd_Update( camwnd );
                CameraMovedNotify();
 
-               Sys_SetCursorPos( GTK_WINDOW( m_parent ), m_PositionDragCursorX, m_PositionDragCursorY );
+               Sys_SetCursorPos( m_parent, m_PositionDragCursorX, m_PositionDragCursorY );
        }
 }
 #endif
@@ -1311,7 +1372,7 @@ void CamWnd::Cam_PositionDrag(){
 
 // NOTE TTimo if there's an OS-level focus out of the application
 //   then we can release the camera cursor grab
-static gboolean camwindow_freemove_focusout( GtkWidget* widget, GdkEventFocus* event, gpointer data ){
+static gboolean camwindow_freemove_focusout( ui::Widget widget, GdkEventFocus* event, gpointer data ){
        reinterpret_cast<CamWnd*>( data )->DisableFreeMove();
        return FALSE;
 }
@@ -1327,7 +1388,7 @@ void CamWnd::EnableFreeMove(){
        CamWnd_Add_Handlers_FreeMove( *this );
 
        gtk_window_set_focus( m_parent, m_gl_widget );
-       m_freemove_handle_focusout = g_signal_connect( G_OBJECT( m_gl_widget ), "focus_out_event", G_CALLBACK( camwindow_freemove_focusout ), this );
+       m_freemove_handle_focusout = m_gl_widget.connect( "focus_out_event", G_CALLBACK( camwindow_freemove_focusout ), this );
        m_freezePointer.freeze_pointer( m_parent, m_gl_widget, Camera_motionDelta, &m_Camera );
 
        CamWnd_Update( *this );
@@ -1386,7 +1447,7 @@ void SetState( Shader* state, EStyle style ){
                m_state_stack.back().m_state = state;
        }
 }
-const EStyle getStyle() const {
+EStyle getStyle() const {
        return eFullMaterials;
 }
 void PushState(){
@@ -1429,24 +1490,30 @@ void render( const Matrix4& modelview, const Matrix4& projection ){
 void ShowStatsToggle(){
        g_camwindow_globals_private.m_showStats ^= 1;
 }
-typedef FreeCaller<ShowStatsToggle> ShowStatsToggleCaller;
 
-void ShowStatsExport( const BoolImportCallback& importer ){
+void ShowStatsExport( const Callback<void(bool)> &importer ){
        importer( g_camwindow_globals_private.m_showStats );
 }
-typedef FreeCaller1<const BoolImportCallback&, ShowStatsExport> ShowStatsExportCaller;
 
-ShowStatsExportCaller g_show_stats_caller;
-BoolExportCallback g_show_stats_callback( g_show_stats_caller );
+FreeCaller<void(const Callback<void(bool)>&), ShowStatsExport> g_show_stats_caller;
+Callback<void(const Callback<void(bool)> &)> g_show_stats_callback( g_show_stats_caller );
 ToggleItem g_show_stats( g_show_stats_callback );
 */
-BoolExportCaller g_show_stats_caller( g_camwindow_globals_private.m_showStats );
-ToggleItem g_show_stats( g_show_stats_caller );
+
 void ShowStatsToggle(){
        g_camwindow_globals_private.m_showStats ^= 1;
-       g_show_stats.update();
+//     g_show_stats.update();
        UpdateAllWindows();
 }
+typedef FreeCaller<void(), ShowStatsToggle> ShowStatsToggleCaller;
+void ShowStatsExport( const Callback<void(bool)> & importer ){
+       importer( g_camwindow_globals_private.m_showStats );
+}
+typedef FreeCaller<void(const Callback<void(bool)> &), ShowStatsExport> ShowStatsExportCaller;
+
+ShowStatsExportCaller g_show_stats_caller;
+Callback<void(const Callback<void(bool)> &)> g_show_stats_callback( g_show_stats_caller );
+ToggleItem g_show_stats( g_show_stats_callback );
 
 void CamWnd::Cam_Draw(){
        glViewport( 0, 0, m_Camera.width, m_Camera.height );
@@ -1640,10 +1707,6 @@ void CamWnd::BenchMark(){
 }
 
 
-void fill_view_camera_menu( GtkMenu* menu ){
-       create_check_menu_item_with_mnemonic( menu, "Camera View", "ToggleCamera" );
-}
-
 void GlobalCamera_ResetAngles(){
        CamWnd& camwnd = *g_camwnd;
        Vector3 angles;
@@ -1652,6 +1715,55 @@ void GlobalCamera_ResetAngles(){
        Camera_setAngles( camwnd, angles );
 }
 
+#include "select.h"
+
+Vector3 Camera_getFocusPos( camera_t& camera ){
+       Vector3 camorigin( Camera_getOrigin( camera ) );
+       AABB aabb( aabb_for_minmax( Select_getWorkZone().d_work_min, Select_getWorkZone().d_work_max ) );
+       View& view = *( camera.m_view );
+#if 0
+       Vector3 angles( Camera_getAngles( camera ) );
+       Vector3 radangles( degrees_to_radians( angles[0] ), degrees_to_radians( angles[1] ), degrees_to_radians( angles[2] ) );
+       Vector3 viewvector;
+       viewvector[0] = cos( radangles[1] ) * cos( radangles[0] );
+       viewvector[1] = sin( radangles[1] ) * cos( radangles[0] );
+       viewvector[2] = sin( radangles[0] );
+#elif 0
+       Vector3 viewvector( -view.GetModelview()[2], -view.GetModelview()[6], -view.GetModelview()[10] );
+#elif 1
+       Vector3 viewvector( -camera.vpn );
+#endif
+
+       Plane3 frustumPlanes[4];
+       frustumPlanes[0] = plane3_translated( view.getFrustum().left, camorigin - aabb.origin );
+       frustumPlanes[1] = plane3_translated( view.getFrustum().right, camorigin - aabb.origin );
+       frustumPlanes[2] = plane3_translated( view.getFrustum().top, camorigin - aabb.origin );
+       frustumPlanes[3] = plane3_translated( view.getFrustum().bottom, camorigin - aabb.origin );
+
+       float offset = 64.0f;
+
+       Vector3 corners[8];
+       aabb_corners( aabb, corners );
+
+       for ( size_t i = 0; i < 4; ++i ){
+               for ( size_t j = 0; j < 8; ++j ){
+                       Ray ray( aabb.origin, -viewvector );
+                       //Plane3 newplane( frustumPlanes[i].normal(), vector3_dot( frustumPlanes[i].normal(), corners[j] - frustumPlanes[i].normal() * 16.0f ) );
+                       Plane3 newplane( frustumPlanes[i].normal(), vector3_dot( frustumPlanes[i].normal(), corners[j] ) );
+                       float d = vector3_dot( ray.direction, newplane.normal() );
+                       if( d != 0 ){
+                               float s = vector3_dot( newplane.normal() * newplane.dist() - ray.origin, newplane.normal() ) / d;
+                               offset = std::max( offset, s );
+                       }
+               }
+       }
+       return ( aabb.origin - viewvector * offset );
+}
+
+void GlobalCamera_FocusOnSelected(){
+       Camera_setOrigin( *g_camwnd, Camera_getFocusPos( g_camwnd->getCamera() ) );
+}
+
 void Camera_ChangeFloorUp(){
        CamWnd& camwnd = *g_camwnd;
        camwnd.Cam_ChangeFloor( true );
@@ -1688,7 +1800,7 @@ bool Camera_GetFarClip(){
        return g_camwindow_globals_private.m_bCubicClipping;
 }
 
-BoolExportCaller g_getfarclip_caller( g_camwindow_globals_private.m_bCubicClipping );
+ConstReferenceCaller<bool, void(const Callback<void(bool)> &), PropertyImpl<bool>::Export> g_getfarclip_caller( g_camwindow_globals_private.m_bCubicClipping );
 ToggleItem g_getfarclip_item( g_getfarclip_caller );
 
 void Camera_SetFarClip( bool value ){
@@ -1699,12 +1811,22 @@ void Camera_SetFarClip( bool value ){
        CamWnd_Update( camwnd );
 }
 
+struct Camera_FarClip {
+       static void Export(const Callback<void(bool)> &returnz) {
+               returnz(g_camwindow_globals_private.m_bCubicClipping);
+       }
+
+       static void Import(bool value) {
+               Camera_SetFarClip(value);
+       }
+};
+
 void Camera_ToggleFarClip(){
        Camera_SetFarClip( !Camera_GetFarClip() );
 }
 
 
-void CamWnd_constructToolbar( GtkToolbar* toolbar ){
+void CamWnd_constructToolbar( ui::Toolbar toolbar ){
        toolbar_append_toggle_button( toolbar, "Cubic clip the camera view (Ctrl + \\)", "view_cubicclipping.png", "ToggleCubicClip" );
 }
 
@@ -1757,7 +1879,7 @@ CameraModel* g_camera_model = 0;
 void CamWnd_LookThroughCamera( CamWnd& camwnd ){
        if ( g_camera_model != 0 ) {
                CamWnd_Add_Handlers_Move( camwnd );
-               g_camera_model->setCameraView( 0, Callback() );
+               g_camera_model->setCameraView( 0, Callback<void()>() );
                g_camera_model = 0;
                Camera_updateModelview( camwnd.getCamera() );
                Camera_updateProjection( camwnd.getCamera() );
@@ -1780,7 +1902,7 @@ void CamWnd_LookThroughSelected( CamWnd& camwnd ){
                if ( cameraModel != 0 ) {
                        CamWnd_Remove_Handlers_Move( camwnd );
                        g_camera_model = cameraModel;
-                       g_camera_model->setCameraView( &camwnd.getCameraView(), ReferenceCaller<CamWnd, CamWnd_LookThroughCamera>( camwnd ) );
+                       g_camera_model->setCameraView( &camwnd.getCameraView(), ReferenceCaller<CamWnd, void(), CamWnd_LookThroughCamera>( camwnd ) );
                }
        }
 }
@@ -1793,10 +1915,26 @@ void GlobalCamera_LookThroughCamera(){
        CamWnd_LookThroughCamera( *g_camwnd );
 }
 
+struct RenderMode {
+       static void Export(const Callback<void(int)> &returnz) {
+               switch (CamWnd_GetMode()) {
+                       case cd_wire:
+                               returnz(0);
+                               break;
+                       case cd_solid:
+                               returnz(1);
+                               break;
+                       case cd_texture:
+                               returnz(2);
+                               break;
+                       case cd_lighting:
+                               returnz(3);
+                               break;
+               }
+       }
 
-void RenderModeImport( int value ){
-       switch ( value )
-       {
+       static void Import(int value) {
+               switch (value) {
        case 0:
                CamWnd_SetMode( cd_wire );
                break;
@@ -1813,41 +1951,21 @@ void RenderModeImport( int value ){
                CamWnd_SetMode( cd_texture );
        }
 }
-typedef FreeCaller1<int, RenderModeImport> RenderModeImportCaller;
-
-void RenderModeExport( const IntImportCallback& importer ){
-       switch ( CamWnd_GetMode() )
-       {
-       case cd_wire:
-               importer( 0 );
-               break;
-       case cd_solid:
-               importer( 1 );
-               break;
-       case cd_texture:
-               importer( 2 );
-               break;
-       case cd_lighting:
-               importer( 3 );
-               break;
-       }
-}
-typedef FreeCaller1<const IntImportCallback&, RenderModeExport> RenderModeExportCaller;
+};
 
 void Camera_constructPreferences( PreferencesPage& page ){
        page.appendSlider( "Movement Speed", g_camwindow_globals_private.m_nMoveSpeed, TRUE, 0, 0, 100, MIN_CAM_SPEED, MAX_CAM_SPEED, 1, 10 );
        page.appendCheckBox( "", "Link strafe speed to movement speed", g_camwindow_globals_private.m_bCamLinkSpeed );
        page.appendSlider( "Rotation Speed", g_camwindow_globals_private.m_nAngleSpeed, TRUE, 0, 0, 3, 1, 180, 1, 10 );
        page.appendCheckBox( "", "Invert mouse vertical axis", g_camwindow_globals_private.m_bCamInverseMouse );
+       page.appendCheckBox( "", "Zoom In to Mouse pointer", g_camwindow_globals.m_bZoomInToPointer );
        page.appendCheckBox(
                "", "Discrete movement",
-               FreeCaller1<bool, CamWnd_Move_Discrete_Import>(),
-               BoolExportCaller( g_camwindow_globals_private.m_bCamDiscrete )
+               make_property<CamWnd_Move_Discrete>()
                );
        page.appendCheckBox(
                "", "Enable far-clip plane",
-               FreeCaller1<bool, Camera_SetFarClip>(),
-               BoolExportCaller( g_camwindow_globals_private.m_bCubicClipping )
+               make_property<Camera_FarClip>()
                );
 
        if ( g_pGameDescription->mGameType == "doom3" ) {
@@ -1856,8 +1974,7 @@ void Camera_constructPreferences( PreferencesPage& page ){
                page.appendCombo(
                        "Render Mode",
                        STRING_ARRAY_RANGE( render_mode ),
-                       IntImportCallback( RenderModeImportCaller() ),
-                       IntExportCallback( RenderModeExportCaller() )
+                       make_property<RenderMode>()
                        );
        }
        else
@@ -1867,12 +1984,11 @@ void Camera_constructPreferences( PreferencesPage& page ){
                page.appendCombo(
                        "Render Mode",
                        STRING_ARRAY_RANGE( render_mode ),
-                       IntImportCallback( RenderModeImportCaller() ),
-                       IntExportCallback( RenderModeExportCaller() )
+                       make_property<RenderMode>()
                        );
        }
 
-       const char* strafe_mode[] = { "Both", "Forward", "Up" };
+       const char* strafe_mode[] = { "None", "Up", "Forward", "Both", "Both Inverted" };
 
        page.appendCombo(
                "Strafe Mode",
@@ -1885,15 +2001,13 @@ void Camera_constructPage( PreferenceGroup& group ){
        Camera_constructPreferences( page );
 }
 void Camera_registerPreferencesPage(){
-       PreferencesDialog_addSettingsPage( FreeCaller1<PreferenceGroup&, Camera_constructPage>() );
+       PreferencesDialog_addSettingsPage( makeCallbackF(Camera_constructPage) );
 }
 
 #include "preferencesystem.h"
 #include "stringio.h"
 #include "dialog.h"
 
-typedef FreeCaller1<bool, CamWnd_Move_Discrete_Import> CamWndMoveDiscreteImportCaller;
-
 void CameraSpeed_increase(){
        if ( g_camwindow_globals_private.m_nMoveSpeed <= ( MAX_CAM_SPEED - CAM_SPEED_STEP - 10 ) ) {
                g_camwindow_globals_private.m_nMoveSpeed += CAM_SPEED_STEP;
@@ -1914,30 +2028,31 @@ void CameraSpeed_decrease(){
 
 /// \brief Initialisation for things that have the same lifespan as this module.
 void CamWnd_Construct(){
-       GlobalCommands_insert( "CenterView", FreeCaller<GlobalCamera_ResetAngles>(), Accelerator( GDK_End ) );
+       GlobalCommands_insert( "CenterView", makeCallbackF(GlobalCamera_ResetAngles), Accelerator( GDK_KEY_End ) );
+       GlobalCommands_insert( "CameraFocusOnSelected", makeCallbackF( GlobalCamera_FocusOnSelected ), Accelerator( GDK_Tab ) );
 
-       GlobalToggles_insert( "ToggleCubicClip", FreeCaller<Camera_ToggleFarClip>(), ToggleItem::AddCallbackCaller( g_getfarclip_item ), Accelerator( '\\', (GdkModifierType)GDK_CONTROL_MASK ) );
-       GlobalCommands_insert( "CubicClipZoomIn", FreeCaller<Camera_CubeIn>(), Accelerator( '[', (GdkModifierType)GDK_CONTROL_MASK ) );
-       GlobalCommands_insert( "CubicClipZoomOut", FreeCaller<Camera_CubeOut>(), Accelerator( ']', (GdkModifierType)GDK_CONTROL_MASK ) );
+       GlobalToggles_insert( "ToggleCubicClip", makeCallbackF(Camera_ToggleFarClip), ToggleItem::AddCallbackCaller( g_getfarclip_item ), Accelerator( '\\', (GdkModifierType)GDK_CONTROL_MASK ) );
+       GlobalCommands_insert( "CubicClipZoomIn", makeCallbackF(Camera_CubeIn), Accelerator( '[', (GdkModifierType)GDK_CONTROL_MASK ) );
+       GlobalCommands_insert( "CubicClipZoomOut", makeCallbackF(Camera_CubeOut), Accelerator( ']', (GdkModifierType)GDK_CONTROL_MASK ) );
 
-       GlobalCommands_insert( "UpFloor", FreeCaller<Camera_ChangeFloorUp>(), Accelerator( GDK_Prior ) );
-       GlobalCommands_insert( "DownFloor", FreeCaller<Camera_ChangeFloorDown>(), Accelerator( GDK_Next ) );
+       GlobalCommands_insert( "UpFloor", makeCallbackF(Camera_ChangeFloorUp), Accelerator( GDK_KEY_Prior ) );
+       GlobalCommands_insert( "DownFloor", makeCallbackF(Camera_ChangeFloorDown), Accelerator( GDK_KEY_Next ) );
 
        GlobalToggles_insert( "ToggleCamera", ToggleShown::ToggleCaller( g_camera_shown ), ToggleItem::AddCallbackCaller( g_camera_shown.m_item ), Accelerator( 'C', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
-       GlobalCommands_insert( "LookThroughSelected", FreeCaller<GlobalCamera_LookThroughSelected>() );
-       GlobalCommands_insert( "LookThroughCamera", FreeCaller<GlobalCamera_LookThroughCamera>() );
+//     GlobalCommands_insert( "LookThroughSelected", makeCallbackF(GlobalCamera_LookThroughSelected) );
+//     GlobalCommands_insert( "LookThroughCamera", makeCallbackF(GlobalCamera_LookThroughCamera) );
 
        if ( g_pGameDescription->mGameType == "doom3" ) {
-               GlobalCommands_insert( "TogglePreview", FreeCaller<CamWnd_TogglePreview>(), Accelerator( GDK_F3 ) );
+               GlobalCommands_insert( "TogglePreview", makeCallbackF(CamWnd_TogglePreview), Accelerator( GDK_KEY_F3 ) );
        }
 
-       GlobalCommands_insert( "CameraSpeedInc", FreeCaller<CameraSpeed_increase>(), Accelerator( GDK_KP_Add, (GdkModifierType)GDK_SHIFT_MASK ) );
-       GlobalCommands_insert( "CameraSpeedDec", FreeCaller<CameraSpeed_decrease>(), Accelerator( GDK_KP_Subtract, (GdkModifierType)GDK_SHIFT_MASK ) );
+       GlobalCommands_insert( "CameraSpeedInc", makeCallbackF(CameraSpeed_increase), Accelerator( GDK_KEY_KP_Add, (GdkModifierType)GDK_SHIFT_MASK ) );
+       GlobalCommands_insert( "CameraSpeedDec", makeCallbackF(CameraSpeed_decrease), Accelerator( GDK_KEY_KP_Subtract, (GdkModifierType)GDK_SHIFT_MASK ) );
 
-       GlobalShortcuts_insert( "CameraForward", Accelerator( GDK_Up ) );
-       GlobalShortcuts_insert( "CameraBack", Accelerator( GDK_Down ) );
-       GlobalShortcuts_insert( "CameraLeft", Accelerator( GDK_Left ) );
-       GlobalShortcuts_insert( "CameraRight", Accelerator( GDK_Right ) );
+       GlobalShortcuts_insert( "CameraForward", Accelerator( GDK_KEY_Up ) );
+       GlobalShortcuts_insert( "CameraBack", Accelerator( GDK_KEY_Down ) );
+       GlobalShortcuts_insert( "CameraLeft", Accelerator( GDK_KEY_Left ) );
+       GlobalShortcuts_insert( "CameraRight", Accelerator( GDK_KEY_Right ) );
        GlobalShortcuts_insert( "CameraStrafeRight", Accelerator( 'D' ) );
        GlobalShortcuts_insert( "CameraStrafeLeft", Accelerator( 'A' ) );
 
@@ -1951,25 +2066,31 @@ void CamWnd_Construct(){
        GlobalShortcuts_insert( "CameraFreeMoveLeft", Accelerator( 'A' ) );
        GlobalShortcuts_insert( "CameraFreeMoveRight", Accelerator( 'D' ) );
 
-       GlobalShortcuts_insert( "CameraFreeMoveForward2", Accelerator( GDK_Up ) );
-       GlobalShortcuts_insert( "CameraFreeMoveBack2", Accelerator( GDK_Down ) );
-       GlobalShortcuts_insert( "CameraFreeMoveLeft2", Accelerator( GDK_Left ) );
-       GlobalShortcuts_insert( "CameraFreeMoveRight2", Accelerator( GDK_Right ) );
-
-       GlobalToggles_insert( "ShowStats", FreeCaller<ShowStatsToggle>(), ToggleItem::AddCallbackCaller( g_show_stats ) );
-
-       GlobalPreferenceSystem().registerPreference( "ShowStats", BoolImportStringCaller( g_camwindow_globals_private.m_showStats ), BoolExportStringCaller( g_camwindow_globals_private.m_showStats ) );
-       GlobalPreferenceSystem().registerPreference( "MoveSpeed", IntImportStringCaller( g_camwindow_globals_private.m_nMoveSpeed ), IntExportStringCaller( g_camwindow_globals_private.m_nMoveSpeed ) );
-       GlobalPreferenceSystem().registerPreference( "CamLinkSpeed", BoolImportStringCaller( g_camwindow_globals_private.m_bCamLinkSpeed ), BoolExportStringCaller( g_camwindow_globals_private.m_bCamLinkSpeed ) );
-       GlobalPreferenceSystem().registerPreference( "AngleSpeed", IntImportStringCaller( g_camwindow_globals_private.m_nAngleSpeed ), IntExportStringCaller( g_camwindow_globals_private.m_nAngleSpeed ) );
-       GlobalPreferenceSystem().registerPreference( "CamInverseMouse", BoolImportStringCaller( g_camwindow_globals_private.m_bCamInverseMouse ), BoolExportStringCaller( g_camwindow_globals_private.m_bCamInverseMouse ) );
-       GlobalPreferenceSystem().registerPreference( "CamDiscrete", makeBoolStringImportCallback( CamWndMoveDiscreteImportCaller() ), BoolExportStringCaller( g_camwindow_globals_private.m_bCamDiscrete ) );
-       GlobalPreferenceSystem().registerPreference( "CubicClipping", BoolImportStringCaller( g_camwindow_globals_private.m_bCubicClipping ), BoolExportStringCaller( g_camwindow_globals_private.m_bCubicClipping ) );
-       GlobalPreferenceSystem().registerPreference( "CubicScale", IntImportStringCaller( g_camwindow_globals.m_nCubicScale ), IntExportStringCaller( g_camwindow_globals.m_nCubicScale ) );
-       GlobalPreferenceSystem().registerPreference( "SI_Colors4", Vector3ImportStringCaller( g_camwindow_globals.color_cameraback ), Vector3ExportStringCaller( g_camwindow_globals.color_cameraback ) );
-       GlobalPreferenceSystem().registerPreference( "SI_Colors12", Vector3ImportStringCaller( g_camwindow_globals.color_selbrushes3d ), Vector3ExportStringCaller( g_camwindow_globals.color_selbrushes3d ) );
-       GlobalPreferenceSystem().registerPreference( "CameraRenderMode", makeIntStringImportCallback( RenderModeImportCaller() ), makeIntStringExportCallback( RenderModeExportCaller() ) );
-       GlobalPreferenceSystem().registerPreference( "StrafeMode", IntImportStringCaller( g_camwindow_globals_private.m_nStrafeMode ), IntExportStringCaller( g_camwindow_globals_private.m_nStrafeMode ) );
+       GlobalShortcuts_insert( "CameraFreeMoveForward2", Accelerator( GDK_KEY_Up ) );
+       GlobalShortcuts_insert( "CameraFreeMoveBack2", Accelerator( GDK_KEY_Down ) );
+       GlobalShortcuts_insert( "CameraFreeMoveLeft2", Accelerator( GDK_KEY_Left ) );
+       GlobalShortcuts_insert( "CameraFreeMoveRight2", Accelerator( GDK_KEY_Right ) );
+
+       GlobalShortcuts_insert( "CameraFreeMoveUp", accelerator_null() );
+       GlobalShortcuts_insert( "CameraFreeMoveDown", accelerator_null() );
+
+       GlobalShortcuts_insert( "CameraFreeFocus", Accelerator( GDK_Tab ) );
+
+       GlobalToggles_insert( "ShowStats", makeCallbackF(ShowStatsToggle), ToggleItem::AddCallbackCaller( g_show_stats ) );
+
+       GlobalPreferenceSystem().registerPreference( "ShowStats", make_property_string( g_camwindow_globals_private.m_showStats ) );
+       GlobalPreferenceSystem().registerPreference( "MoveSpeed", make_property_string( g_camwindow_globals_private.m_nMoveSpeed ) );
+       GlobalPreferenceSystem().registerPreference( "CamLinkSpeed", make_property_string( g_camwindow_globals_private.m_bCamLinkSpeed ) );
+       GlobalPreferenceSystem().registerPreference( "AngleSpeed", make_property_string( g_camwindow_globals_private.m_nAngleSpeed ) );
+       GlobalPreferenceSystem().registerPreference( "CamInverseMouse", make_property_string( g_camwindow_globals_private.m_bCamInverseMouse ) );
+       GlobalPreferenceSystem().registerPreference( "CamDiscrete", make_property_string<CamWnd_Move_Discrete>());
+       GlobalPreferenceSystem().registerPreference( "CubicClipping", make_property_string( g_camwindow_globals_private.m_bCubicClipping ) );
+       GlobalPreferenceSystem().registerPreference( "CubicScale", make_property_string( g_camwindow_globals.m_nCubicScale ) );
+       GlobalPreferenceSystem().registerPreference( "SI_Colors4", make_property_string( g_camwindow_globals.color_cameraback ) );
+       GlobalPreferenceSystem().registerPreference( "SI_Colors12", make_property_string( g_camwindow_globals.color_selbrushes3d ) );
+       GlobalPreferenceSystem().registerPreference( "CameraRenderMode", make_property_string<RenderMode>() );
+       GlobalPreferenceSystem().registerPreference( "StrafeMode", make_property_string( g_camwindow_globals_private.m_nStrafeMode ) );
+       GlobalPreferenceSystem().registerPreference( "3DZoomInToPointer", make_property_string( g_camwindow_globals.m_bZoomInToPointer ) );
 
        CamWnd_constructStatic();