]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/xywindow.cpp
Merge commit 'e78f526d5fbbbf18699ec76297e4973565356c81' into master-merge
[xonotic/netradiant.git] / radiant / xywindow.cpp
index baf3f621c2b71c8bec337f65f881e801eed03807..3470f861b0834c25f984a62caf646eb0461cea7c 100644 (file)
@@ -58,6 +58,7 @@
 #include "gtkutil/widget.h"
 #include "gtkutil/glwidget.h"
 #include "gtkutil/filechooser.h"
+#include "gtkutil/cursor.h"
 #include "gtkmisc.h"
 #include "select.h"
 #include "csg.h"
@@ -500,17 +501,17 @@ void XYWnd::SetScale( float f ){
        XYWnd_Update( *this );
 }
 
-void XYWnd_ZoomIn( XYWnd* xy ){
+void XYWnd::ZoomIn(){
        float max_scale = 64;
-       float scale = xy->Scale() * 5.0f / 4.0f;
+       float scale = Scale() * 5.0f / 4.0f;
        if ( scale > max_scale ) {
-               if ( xy->Scale() != max_scale ) {
-                       xy->SetScale( max_scale );
+               if ( Scale() != max_scale ) {
+                       SetScale( max_scale );
                }
        }
        else
        {
-               xy->SetScale( scale );
+               SetScale( scale );
        }
 }
 
@@ -518,17 +519,44 @@ void XYWnd_ZoomIn( XYWnd* xy ){
 // NOTE: the zoom out factor is 4/5, we could think about customizing it
 //  we don't go below a zoom factor corresponding to 10% of the max world size
 //  (this has to be computed against the window size)
-void XYWnd_ZoomOut( XYWnd* xy ){
-       float min_scale = MIN( xy->Width(),xy->Height() ) / ( 1.1f * ( g_MaxWorldCoord - g_MinWorldCoord ) );
-       float scale = xy->Scale() * 4.0f / 5.0f;
+void XYWnd::ZoomOut(){
+       float min_scale = MIN( Width(), Height() ) / ( 1.1f * ( g_MaxWorldCoord - g_MinWorldCoord ) );
+       float scale = Scale() * 4.0f / 5.0f;
        if ( scale < min_scale ) {
-               if ( xy->Scale() != min_scale ) {
-                       xy->SetScale( min_scale );
+               if ( Scale() != min_scale ) {
+                       SetScale( min_scale );
                }
        }
        else
        {
-               xy->SetScale( scale );
+               SetScale( scale );
+       }
+}
+
+void XYWnd::ZoomInWithMouse( int pointx, int pointy ){
+       float old_scale = Scale();
+       ZoomIn();
+       if ( g_xywindow_globals.m_bImprovedWheelZoom ) {
+               float scale_diff = 1.0 / old_scale - 1.0 / Scale();
+               int nDim1 = ( m_viewType == YZ ) ? 1 : 0;
+               int nDim2 = ( m_viewType == XY ) ? 1 : 2;
+               Vector3 origin = GetOrigin();
+               origin[nDim1] += scale_diff * (pointx - 0.5 * Width());
+               origin[nDim2] -= scale_diff * (pointy - 0.5 * Height());
+               SetOrigin( origin );
+       }
+}
+
+void XYWnd::Redraw() {
+       if ( glwidget_make_current( m_gl_widget ) != FALSE ) {
+               if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) {
+                       GlobalOpenGL_debugAssertNoErrors();
+                       XY_Draw();
+                       GlobalOpenGL_debugAssertNoErrors();
+
+                       m_XORRectangle.set( rectangle_t() );
+               }
+               glwidget_swap_buffers( m_gl_widget );
        }
 }
 
@@ -711,7 +739,16 @@ Shader* XYWnd::m_state_selected = 0;
 
 void xy_update_xor_rectangle( XYWnd& self, rect_t area ){
        if ( self.GetWidget().visible() ) {
-               self.m_XORRectangle.set( rectangle_from_area( area.min, area.max, self.Width(), self.Height() ) );
+               rectangle_t rect = rectangle_from_area( area.min, area.max, self.Width(), self.Height() );
+               int nDim1 = ( self.GetViewType() == YZ ) ? 1 : 0;
+               int nDim2 = ( self.GetViewType() == XY ) ? 1 : 2;
+               rect.x /= self.Scale();
+               rect.y /= self.Scale();
+               rect.w /= self.Scale();
+               rect.h /= self.Scale();
+               rect.x += self.GetOrigin()[nDim1];
+               rect.y += self.GetOrigin()[nDim2];
+               self.m_XORRectangle.set( rect );
        }
 }
 
@@ -753,10 +790,10 @@ void xywnd_motion( gdouble x, gdouble y, guint state, void* data ){
 
 gboolean xywnd_wheel_scroll( ui::Widget widget, GdkEventScroll* event, XYWnd* xywnd ){
        if ( event->direction == GDK_SCROLL_UP ) {
-               XYWnd_ZoomIn( xywnd );
+               xywnd->ZoomInWithMouse( (int)event->x, (int)event->y );
        }
        else if ( event->direction == GDK_SCROLL_DOWN ) {
-               XYWnd_ZoomOut( xywnd );
+               xywnd->ZoomOut();
        }
        return FALSE;
 }
@@ -770,20 +807,10 @@ gboolean xywnd_size_allocate( ui::Widget widget, GtkAllocation* allocation, XYWn
 }
 
 gboolean xywnd_expose( ui::Widget widget, GdkEventExpose* event, XYWnd* xywnd ){
-       if ( glwidget_make_current( xywnd->GetWidget() ) != FALSE ) {
-               if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) {
-                       GlobalOpenGL_debugAssertNoErrors();
-                       xywnd->XY_Draw();
-                       GlobalOpenGL_debugAssertNoErrors();
-
-                       xywnd->m_XORRectangle.set( rectangle_t() );
-               }
-               glwidget_swap_buffers( xywnd->GetWidget() );
-       }
+       xywnd->Redraw();
        return FALSE;
 }
 
-
 void XYWnd_CameraMoved( XYWnd& xywnd ){
        if ( g_xywindow_globals_private.m_bCamXYUpdate ) {
                XYWnd_Update( xywnd );
@@ -797,7 +824,8 @@ XYWnd::XYWnd() :
        m_parent( ui::null ),
        m_window_observer( NewWindowObserver() ),
        m_XORRectangle( m_gl_widget ),
-       m_chasemouse_handler( 0 ){
+       m_chasemouse_handler( 0 ) {
+
        m_bActive = false;
        m_buttonstate = 0;
 
@@ -848,8 +876,11 @@ XYWnd::XYWnd() :
 
        Map_addValidCallback( g_map, DeferredDrawOnMapValidChangedCaller( m_deferredDraw ) );
 
-       updateProjection();
-       updateModelview();
+       // This reconstruct=false argument is used to avoid a circular dependency
+       // between modelview and projection initialization and a valgrind complaint
+       updateProjection( false );
+       updateModelview( false );
+       m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
 
        AddSceneChangeCallback( ReferenceCaller<XYWnd, void(), &XYWnd_Update>( *this ) );
        AddCameraMovedCallback( ReferenceCaller<XYWnd, void(), &XYWnd_CameraMoved>( *this ) );
@@ -947,14 +978,11 @@ void XYWnd::Clipper_Crosshair_OnMouseMoved( int x, int y ){
        Vector3 mousePosition;
        XY_ToPoint( x, y, mousePosition );
        if ( ClipMode() && GlobalClipPoints_Find( mousePosition, (VIEWTYPE)m_viewType, m_fScale ) != 0 ) {
-               GdkCursor *cursor;
-               cursor = gdk_cursor_new( GDK_CROSSHAIR );
-               gdk_window_set_cursor( gtk_widget_get_window(m_gl_widget), cursor );
-               gdk_cursor_unref( cursor );
+               set_cursor ( m_gl_widget, GDK_CROSSHAIR );
        }
        else
        {
-               gdk_window_set_cursor( gtk_widget_get_window(m_gl_widget), 0 );
+               default_cursor( m_gl_widget );
        }
 }
 
@@ -1071,11 +1099,11 @@ void entitycreate_activated( ui::Widget item ){
                g_pParentWnd->ActiveXY()->OnEntityCreate( entity_name );
        }
        else {
-               GlobalRadiant().m_pfnMessageBox( MainFrame_getWindow(), "There's already a worldspawn in your map!"
-                                                                                                                                                         "",
-                                                                                "Info",
-                                                                                eMB_OK,
-                                                                                eMB_ICONDEFAULT );
+               GlobalRadiant().m_pfnMessageBox( MainFrame_getWindow(),
+                       "There's already a worldspawn in your map!",
+                       "Info",
+                       eMB_OK,
+                       eMB_ICONDEFAULT );
        }
 }
 
@@ -1187,13 +1215,13 @@ void XYWnd::Move_Begin(){
                Move_End();
        }
        m_move_started = true;
-       g_xywnd_freezePointer.freeze_pointer( m_parent  ? m_parent : MainFrame_getWindow(), XYWnd_moveDelta, this );
+       g_xywnd_freezePointer.freeze_pointer( m_gl_widget, XYWnd_moveDelta, this );
        m_move_focusOut = m_gl_widget.connect( "focus_out_event", G_CALLBACK( XYWnd_Move_focusOut ), this );
 }
 
 void XYWnd::Move_End(){
        m_move_started = false;
-       g_xywnd_freezePointer.unfreeze_pointer( m_parent ? m_parent : MainFrame_getWindow() );
+       g_xywnd_freezePointer.unfreeze_pointer( m_gl_widget );
        g_signal_handler_disconnect( G_OBJECT( m_gl_widget ), m_move_focusOut );
 }
 
@@ -1206,16 +1234,15 @@ int g_dragZoom = 0;
 void XYWnd_zoomDelta( int x, int y, unsigned int state, void* data ){
        if ( y != 0 ) {
                g_dragZoom += y;
-
                while ( abs( g_dragZoom ) > 8 )
                {
                        if ( g_dragZoom > 0 ) {
-                               XYWnd_ZoomOut( reinterpret_cast<XYWnd*>( data ) );
+                               reinterpret_cast<XYWnd*>( data )->ZoomOut();
                                g_dragZoom -= 8;
                        }
                        else
                        {
-                               XYWnd_ZoomIn( reinterpret_cast<XYWnd*>( data ) );
+                               reinterpret_cast<XYWnd*>( data )->ZoomIn();
                                g_dragZoom += 8;
                        }
                }
@@ -1489,17 +1516,25 @@ void XYWnd::XY_DisableBackground( void ){
 
 void WXY_BackgroundSelect( void ){
        bool brushesSelected = Scene_countSelectedBrushes( GlobalSceneGraph() ) != 0;
+
+       ui::Window main_window = MainFrame_getWindow();
+
        if ( !brushesSelected ) {
-               ui::alert( ui::root, "You have to select some brushes to get the bounding box for.\n",
+               ui::alert( main_window, "You have to select some brushes to get the bounding box for.\n",
                                                "No selection", ui::alert_type::OK, ui::alert_icon::Error );
                return;
        }
 
-       const char *filename = MainFrame_getWindow().file_dialog( TRUE, "Background Image", NULL, NULL );
+       const char *filename = main_window.file_dialog( TRUE, "Background Image", NULL, NULL );
+
        g_pParentWnd->ActiveXY()->XY_DisableBackground();
+
        if ( filename ) {
                g_pParentWnd->ActiveXY()->XY_LoadBackgroundImage( filename );
        }
+
+       // Draw the background image immediately (do not wait for user input).
+       g_pParentWnd->ActiveXY()->Redraw();
 }
 
 /*
@@ -2103,7 +2138,7 @@ RenderStateFlags m_globalstate;
 Shader* m_state_selected;
 };
 
-void XYWnd::updateProjection(){
+void XYWnd::updateProjection( bool reconstruct ){
        m_projection[0] = 1.0f / static_cast<float>( m_nWidth / 2 );
        m_projection[5] = 1.0f / static_cast<float>( m_nHeight / 2 );
        m_projection[10] = 1.0f / ( g_MaxWorldCoord * m_fScale );
@@ -2126,11 +2161,13 @@ void XYWnd::updateProjection(){
 
        m_projection[15] = 1.0f;
 
-       m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
+       if (reconstruct) {
+               m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
+       }
 }
 
 // note: modelview matrix must have a uniform scale, otherwise strange things happen when rendering the rotation manipulator.
-void XYWnd::updateModelview(){
+void XYWnd::updateModelview( bool reconstruct ){
        int nDim1 = ( m_viewType == YZ ) ? 1 : 0;
        int nDim2 = ( m_viewType == XY ) ? 1 : 2;
 
@@ -2186,7 +2223,9 @@ void XYWnd::updateModelview(){
        m_modelview[3] = m_modelview[7] = m_modelview[11] = 0;
        m_modelview[15] = 1;
 
-       m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
+       if (reconstruct) {
+               m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
+       }
 }
 
 /*
@@ -2513,14 +2552,14 @@ void XY_Zoom100(){
 }
 
 void XY_ZoomIn(){
-       XYWnd_ZoomIn( g_pParentWnd->ActiveXY() );
+       g_pParentWnd->ActiveXY()->ZoomIn();
 }
 
 // NOTE: the zoom out factor is 4/5, we could think about customizing it
 //  we don't go below a zoom factor corresponding to 10% of the max world size
 //  (this has to be computed against the window size)
 void XY_ZoomOut(){
-       XYWnd_ZoomOut( g_pParentWnd->ActiveXY() );
+       g_pParentWnd->ActiveXY()->ZoomOut();
 }
 
 
@@ -2760,6 +2799,7 @@ void XYWindow_Construct(){
        GlobalPreferenceSystem().registerPreference( "ClipCaulk", make_property_string( g_clip_useCaulk ) );
 
        GlobalPreferenceSystem().registerPreference( "NewRightClick", make_property_string( g_xywindow_globals.m_bRightClick ) );
+       GlobalPreferenceSystem().registerPreference( "ImprovedWheelZoom", make_property_string( g_xywindow_globals.m_bImprovedWheelZoom ) );
        GlobalPreferenceSystem().registerPreference( "ChaseMouse", make_property_string( g_xywindow_globals_private.m_bChaseMouse ) );
        GlobalPreferenceSystem().registerPreference( "SizePainting", make_property_string( g_xywindow_globals_private.m_bSizePaint ) );
        GlobalPreferenceSystem().registerPreference( "ShowCrosshair", make_property_string( g_xywindow_globals_private.g_bCrossHairs ) );