/* * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors. * * Graphics Abstraction Layer (GAL) - base class * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef GRAPHICSABSTRACTIONLAYER_H_ #define GRAPHICSABSTRACTIONLAYER_H_ #include #include #include #include #include #include #include #include #include #include class SHAPE_LINE_CHAIN; class SHAPE_POLY_SET; class BITMAP_BASE; namespace KIGFX { /** * Abstract interface for drawing on a 2D-surface. * * The functions are optimized for drawing shapes of an EDA-program such as KiCad. Most methods * are abstract and need to be implemented by a lower layer, for example by a Cairo or OpenGL * implementation. Almost all methods use world coordinates as arguments. The board design is * defined in world space units for drawing purposes these are transformed to screen units with * this layer. So zooming is handled here as well. * */ class GAL : GAL_DISPLAY_OPTIONS_OBSERVER { // These friend declarations allow us to hide routines that should not be called. The // corresponding RAII objects must be used instead. friend class GAL_CONTEXT_LOCKER; friend class GAL_UPDATE_CONTEXT; friend class GAL_DRAWING_CONTEXT; public: // Constructor / Destructor GAL( GAL_DISPLAY_OPTIONS& aOptions ); virtual ~GAL(); /// Return the initialization status for the canvas. virtual bool IsInitialized() const { return true; } /// Return true if the GAL canvas is visible on the screen. virtual bool IsVisible() const { return true; } /// Return true if the GAL engine is a Cairo based type. virtual bool IsCairoEngine() { return false; } /// Return true if the GAL engine is a OpenGL based type. virtual bool IsOpenGlEngine() { return false; } // --------------- // Drawing methods // --------------- /** * Draw a line. * * Start and end points are defined as 2D-Vectors. * * @param aStartPoint is the start point of the line. * @param aEndPoint is the end point of the line. */ virtual void DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) {}; /** * Draw a rounded segment. * * Start and end points are defined as 2D-Vectors. * * @param aStartPoint is the start point of the segment. * @param aEndPoint is the end point of the segment. * @param aWidth is a width of the segment */ virtual void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ){}; /** * Draw a chain of rounded segments. * * @param aPointList is a list of 2D-Vectors containing the chain points. * @param aWidth is a width of the segments */ virtual void DrawSegmentChain( const std::vector& aPointList, double aWidth ){}; virtual void DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ){}; /** * Draw a polyline * * @param aPointList is a list of 2D-Vectors containing the polyline points. */ virtual void DrawPolyline( const std::deque& aPointList ) {}; virtual void DrawPolyline( const std::vector& aPointList ) {}; virtual void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) {}; virtual void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) {}; /** * Draw multiple polylines * * @param aPointLists are lists of 2D-Vectors containing the polyline points. */ virtual void DrawPolylines( const std::vector>& aPointLists ){}; /** * Draw a circle using world coordinates. * * @param aCenterPoint is the center point of the circle. * @param aRadius is the radius of the circle. */ virtual void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) {}; /** * Draw an arc. * * @param aCenterPoint is the center point of the arc. * @param aRadius is the arc radius. * @param aStartAngle is the start angle of the arc. * @param aAngle is the angle of the arc. */ virtual void DrawArc( const VECTOR2D& aCenterPoint, double aRadius, const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aAngle ){}; /** * Draw an arc segment. * * This method differs from DrawArc() in what happens when fill/stroke are on or off. * DrawArc() draws a "pie piece" when fill is turned on, and a thick stroke when fill is off. * DrawArcSegment() with fill *on* behaves like DrawArc() with fill *off*. * DrawArcSegment() with fill *off* draws the outline of what it would have drawn with fill on. * * TODO: Unify Arc routines * * @param aCenterPoint is the center point of the arc. * @param aRadius is the arc radius. * @param aStartAngle is the start angle of the arc. * @param aAngle is the angle of the arc. * @param aWidth is the thickness of the arc (pen size). * @param aMaxError is the max allowed error to create segments to approximate a circle. * It has meaning only for back ends that can't draw a true arc, and use segments to approximate. */ virtual void DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aAngle, double aWidth, double aMaxError ){}; /** * Draw a rectangle. * * @param aStartPoint is the start point of the rectangle. * @param aEndPoint is the end point of the rectangle. */ virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) {}; void DrawRectangle( const BOX2I& aRect ) { DrawRectangle( aRect.GetOrigin(), aRect.GetEnd() ); } /** * Draw a polygon representing a font glyph. */ virtual void DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth = 0, int aTotal = 1 ) {}; /** * Draw polygons representing font glyphs. */ virtual void DrawGlyphs( const std::vector>& aGlyphs ) { for( size_t i = 0; i < aGlyphs.size(); i++ ) DrawGlyph( *aGlyphs[i], i, aGlyphs.size() ); } /** * Draw a polygon. * * @param aPointList is the list of the polygon points. */ virtual void DrawPolygon( const std::deque& aPointList ) {}; virtual void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) {}; virtual void DrawPolygon( const SHAPE_POLY_SET& aPolySet, bool aStrokeTriangulation = false ) {}; virtual void DrawPolygon( const SHAPE_LINE_CHAIN& aPolySet ) {}; /** * Draw a cubic bezier spline. * * @param startPoint is the start point of the spline. * @param controlPointA is the first control point. * @param controlPointB is the second control point. * @param endPoint is the end point of the spline. * @param aFilterValue is used by Bezier to segments approximation, if * the Bezier curve is not supported and needs a curve to polyline conversion. * aFilterValue = 0 means no filtering. */ virtual void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA, const VECTOR2D& controlPointB, const VECTOR2D& endPoint, double aFilterValue = 0.0 ) {}; /** * Draw a bitmap image. */ virtual void DrawBitmap( const BITMAP_BASE& aBitmap, double alphaBlend = 1.0 ) {}; // -------------- // Screen methods // -------------- /// Resize the canvas. virtual void ResizeScreen( int aWidth, int aHeight ) {}; /// Show/hide the GAL canvas virtual bool Show( bool aShow ) { return true; }; /// Return GAL canvas size in pixels const VECTOR2I& GetScreenPixelSize() const { return m_screenSize; } /// Return the swap interval. -1 for adaptive, 0 for disabled/unknown virtual int GetSwapInterval() const { return 0; }; /// Force all remaining objects to be drawn. virtual void Flush() {}; void SetClearColor( const COLOR4D& aColor ) { m_clearColor = aColor; } const COLOR4D& GetClearColor( ) const { return m_clearColor; } /** * Clear the screen. * * @param aColor is the color used for clearing. */ virtual void ClearScreen() {}; // ----------------- // Attribute setting // ----------------- /** * Enable/disable fill. * * @param aIsFillEnabled is true, when the graphics objects should be filled, else false. */ virtual void SetIsFill( bool aIsFillEnabled ) { m_isFillEnabled = aIsFillEnabled; } /** * Enable/disable stroked outlines. * * @param aIsStrokeEnabled is true, if the outline of an object should be stroked. */ virtual void SetIsStroke( bool aIsStrokeEnabled ) { m_isStrokeEnabled = aIsStrokeEnabled; } /** * Set the fill color. * * @param aColor is the color for filling. */ virtual void SetFillColor( const COLOR4D& aColor ) { m_fillColor = aColor; } /** * Get the fill color. * * @return the color for filling a outline. */ inline const COLOR4D& GetFillColor() const { return m_fillColor; } /** * Set the stroke color. * * @param aColor is the color for stroking the outline. */ virtual void SetStrokeColor( const COLOR4D& aColor ) { m_strokeColor = aColor; } /** * Get the stroke color. * * @return the color for stroking the outline. */ inline const COLOR4D& GetStrokeColor() const { return m_strokeColor; } /** * Set the line width. * * @param aLineWidth is the line width. */ virtual void SetLineWidth( float aLineWidth ) { m_lineWidth = aLineWidth; } /** * Get the line width. * * @return the actual line width. */ inline float GetLineWidth() const { return m_lineWidth; } /** * Set the depth of the layer (position on the z-axis) * * @param aLayerDepth the layer depth for the objects. */ virtual void SetLayerDepth( double aLayerDepth ) { assert( aLayerDepth <= m_depthRange.y ); assert( aLayerDepth >= m_depthRange.x ); m_layerDepth = aLayerDepth; } // ---- // Text // ---- /** * Draw a text using a bitmap font. It should be faster than StrokeText(), but can be used * only for non-Gerber elements. * * @param aText is the text to be drawn. * @param aPosition is the text position in world coordinates. * @param aAngle is the text rotation angle. */ virtual void BitmapText( const wxString& aText, const VECTOR2I& aPosition, const EDA_ANGLE& aAngle ); /** * Reset text attributes to default styling. FONT TODO: do we need any of this in GAL anymore? * * Normally, custom attributes will be set individually after this, otherwise you can use * SetTextAttributes() */ void ResetTextAttributes(); void SetGlyphSize( const VECTOR2I aSize ) { m_attributes.m_Size = aSize; } const VECTOR2I& GetGlyphSize() const { return m_attributes.m_Size; } inline void SetFontBold( const bool aBold ) { m_attributes.m_Bold = aBold; } inline bool IsFontBold() const { return m_attributes.m_Bold; } inline void SetFontItalic( bool aItalic ) { m_attributes.m_Italic = aItalic; } inline bool IsFontItalic() const { return m_attributes.m_Italic; } inline void SetFontUnderlined( bool aUnderlined ) { m_attributes.m_Underlined = aUnderlined; } inline bool IsFontUnderlined() const { return m_attributes.m_Underlined; } void SetTextMirrored( const bool aMirrored ) { m_attributes.m_Mirrored = aMirrored; } bool IsTextMirrored() const { return m_attributes.m_Mirrored; } void SetHorizontalJustify( const GR_TEXT_H_ALIGN_T aHorizontalJustify ) { m_attributes.m_Halign = aHorizontalJustify; } GR_TEXT_H_ALIGN_T GetHorizontalJustify() const { return m_attributes.m_Halign; } void SetVerticalJustify( const GR_TEXT_V_ALIGN_T aVerticalJustify ) { m_attributes.m_Valign = aVerticalJustify; } GR_TEXT_V_ALIGN_T GetVerticalJustify() const { return m_attributes.m_Valign; } // -------------- // Transformation // -------------- /** * Transform the context. * * @param aTransformation is the transformation matrix. */ virtual void Transform( const MATRIX3x3D& aTransformation ) {}; /** * Rotate the context. * * @param aAngle is the rotation angle in radians. */ virtual void Rotate( double aAngle ) {}; /** * Translate the context. * * @param aTranslation is the translation vector. */ virtual void Translate( const VECTOR2D& aTranslation ) {}; /** * Scale the context. * * @param aScale is the scale factor for the x- and y-axis. */ virtual void Scale( const VECTOR2D& aScale ) {}; /// Save the context. virtual void Save() {}; /// Restore the context. virtual void Restore() {}; // -------------------------------------------- // Group methods // --------------------------------------------- /** * Begin a group. * * A group is a collection of graphic items. * Hierarchical groups are possible, attributes and transformations can be used. * * @return the number of the group. */ virtual int BeginGroup() { return 0; }; /// End the group. virtual void EndGroup() {}; /** * Draw the stored group. * * @param aGroupNumber is the group number. */ virtual void DrawGroup( int aGroupNumber ) {}; /** * Change the color used to draw the group. * * @param aGroupNumber is the group number. * @param aNewColor is the new color. */ virtual void ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor ) {}; /** * Change the depth (Z-axis position) of the group. * * @param aGroupNumber is the group number. * @param aDepth is the new depth. */ virtual void ChangeGroupDepth( int aGroupNumber, int aDepth ) {}; /** * Delete the group from the memory. * * @param aGroupNumber is the group number. */ virtual void DeleteGroup( int aGroupNumber ) {}; /** * Delete all data created during caching of graphic items. */ virtual void ClearCache() {}; // -------------------------------------------------------- // Handling the world <-> screen transformation // -------------------------------------------------------- /// Compute the world <-> screen transformation matrix virtual void ComputeWorldScreenMatrix(); /** * Get the world <-> screen transformation matrix. * * @return the transformation matrix. */ const MATRIX3x3D& GetWorldScreenMatrix() const { return m_worldScreenMatrix; } /** * Get the screen <-> world transformation matrix. * * @return the transformation matrix. */ const MATRIX3x3D& GetScreenWorldMatrix() const { return m_screenWorldMatrix; } /** * Set the world <-> screen transformation matrix. * * @param aMatrix is the 3x3 world <-> screen transformation matrix. */ inline void SetWorldScreenMatrix( const MATRIX3x3D& aMatrix ) { m_worldScreenMatrix = aMatrix; } /** * @return the bounding box of the world that is displayed on screen at the moment */ BOX2D GetVisibleWorldExtents() const; /** * Set the unit length. * * This defines the length [inch] per one integer. For instance a value 0.001 means * that the coordinate [1000, 1000] corresponds with a point at (1 inch, 1 inch) or * 1 mil resolution per integer. */ void SetWorldUnitLength( double aWorldUnitLength ) { m_worldUnitLength = aWorldUnitLength; } void SetScreenSize( const VECTOR2I& aSize ) { m_screenSize = aSize; } /** * Set the dots per inch of the screen. * * This value depends on the user screen, it should be configurable by the application. * For instance a typical notebook with HD+ resolution (1600x900) has 106 DPI. */ void SetScreenDPI( double aScreenDPI ) { m_screenDPI = aScreenDPI; } /** * Get/set the Point in world space to look at. * * This point corresponds with the center of the actual drawing area. */ void SetLookAtPoint( const VECTOR2D& aPoint ) { m_lookAtPoint = aPoint; } const VECTOR2D& GetLookAtPoint() const { return m_lookAtPoint; } void SetZoomFactor( double aZoomFactor ) { m_zoomFactor = aZoomFactor; } double GetZoomFactor() const { return m_zoomFactor; } /** * Get/set the rotation angle (in radians). */ void SetRotation( double aRotation ) { m_rotation = aRotation; } double GetRotation() const { return m_rotation; } /** * Set the range of the layer depth. * * Usually required for the OpenGL implementation, any object outside this range is not drawn. * * The MinDepth (x) is closest to the clipping plane (top) while the MaxDepth (y) is farthest * from the clipping plane (bottom). */ void SetDepthRange( const VECTOR2D& aDepthRange ) { m_depthRange = aDepthRange; } double GetMinDepth() const { return m_depthRange.x; } double GetMaxDepth() const { return m_depthRange.y; } /** * Get the world scale. * * @return the actual world scale factor. */ double GetWorldScale() const { return m_worldScale; } /** * Sets flipping of the screen. * * @param xAxis is the flip flag for the X axis. * @param yAxis is the flip flag for the Y axis. */ inline void SetFlip( bool xAxis, bool yAxis ) { m_globalFlipX = xAxis; m_globalFlipY = yAxis; } bool IsFlippedX() const { return m_globalFlipX; } bool IsFlippedY() const { return m_globalFlipY; } // --------------------------- // Buffer manipulation methods // --------------------------- /** * Set the target for rendering. * * @param aTarget is the new target for rendering. */ virtual void SetTarget( RENDER_TARGET aTarget ) {}; /** * Get the currently used target for rendering. * * @return The current rendering target. */ virtual RENDER_TARGET GetTarget() const { return TARGET_CACHED; }; /** * Clear the target for rendering. * * @param aTarget is the target to be cleared. */ virtual void ClearTarget( RENDER_TARGET aTarget ) {}; /** * Return true if the target exists. * * @param aTarget is the target to be checked. */ virtual bool HasTarget( RENDER_TARGET aTarget ) { return true; }; /** * Set negative draw mode in the renderer. * * When negative mode is enabled, drawn items will subtract from * previously drawn items. This is mainly needed for Gerber * negative item support in Cairo, since unlike in OpenGL, objects * drawn with zero opacity on top of other objects would not normally * mask objects in Cairo. This method is a no-op in OpenGL. * * @param aSetting is true if negative mode should be enabled */ virtual void SetNegativeDrawMode( bool aSetting ) {}; /** * Begins rendering of a differential layer. Used by gerbview's differential mode. * * Differential layers have their drawn objects blended onto the lower layers * differently so we need to end drawing of current objects and start a new * set to be completed with a different blend mode. */ virtual void StartDiffLayer() {}; /** * Ends rendering of a differential layer. Objects drawn after the StartDiffLayer() * will be drawn and composited with a differential blend mode, then drawing is * returned to normal. */ virtual void EndDiffLayer() {}; /** * Begins rendering in a new layer that will be copied to the main * layer in EndNegativesLayer(). * * For Cairo, layers with negative items need a new layer so when * negative layers _CLEAR sections it doesn't delete drawings on layers * below them. No-op in OpenGL */ virtual void StartNegativesLayer(){}; /** * Ends rendering of a negatives layer and draws it to the main layer. * No-op in OpenGL. */ virtual void EndNegativesLayer(){}; // ------------- // Grid methods // ------------- /** * Set the visibility setting of the grid. * * @param aVisibility is the new visibility setting of the grid. */ void SetGridVisibility( bool aVisibility ) { m_gridVisibility = aVisibility; } bool GetGridVisibility() const { return m_gridVisibility; } bool GetGridSnapping() const { return m_options.m_gridSnapping == KIGFX::GRID_SNAPPING::ALWAYS || ( m_gridVisibility && m_options.m_gridSnapping == KIGFX::GRID_SNAPPING::WITH_GRID ); } /** * Set the origin point for the grid. * * @param aGridOrigin is a vector containing the grid origin point, in world coordinates. */ inline void SetGridOrigin( const VECTOR2D& aGridOrigin ) { m_gridOrigin = aGridOrigin; if( m_gridSize.x == 0.0 || m_gridSize.y == 0.0 ) { m_gridOffset = VECTOR2D( 0.0, 0.0); } else { m_gridOffset = VECTOR2D( (long) m_gridOrigin.x % (long) m_gridSize.x, (long) m_gridOrigin.y % (long) m_gridSize.y ); } } inline const VECTOR2D& GetGridOrigin() const { return m_gridOrigin; } /** * Set the grid size. * * @param aGridSize is a vector containing the grid size in x and y direction. */ inline void SetGridSize( const VECTOR2D& aGridSize ) { m_gridSize = aGridSize; // Avoid stupid grid size values: a grid size should be >= 1 in internal units m_gridSize.x = std::max( 1.0, m_gridSize.x ); m_gridSize.y = std::max( 1.0, m_gridSize.y ); m_gridOffset = VECTOR2D( (long) m_gridOrigin.x % (long) m_gridSize.x, (long) m_gridOrigin.y % (long) m_gridSize.y ); } /** * Return the grid size. * * @return A vector containing the grid size in x and y direction. */ inline const VECTOR2D& GetGridSize() const { return m_gridSize; } /** * Return the visible grid size in x and y directions * * @return A vector containing the spacing of visible grid marks */ inline VECTOR2D GetVisibleGridSize() const { VECTOR2D gridScreenSize( m_gridSize ); double gridThreshold = computeMinGridSpacing() / m_worldScale; if( m_gridStyle == GRID_STYLE::SMALL_CROSS ) gridThreshold *= 2.0; // If we cannot display the grid density, scale down by a tick size and // try again. Eventually, we get some representation of the grid while( std::min( gridScreenSize.x, gridScreenSize.y ) <= gridThreshold ) { gridScreenSize = gridScreenSize * static_cast( m_gridTick ); } return gridScreenSize; } /** * Set the grid color. * * @param aGridColor is the grid color, it should have a low alpha value for the best effect. */ inline void SetGridColor( const COLOR4D& aGridColor ) { m_gridColor = aGridColor; } /** * Set the axes color. * * @param aAxesColor is the color to draw the axes if enabled. */ inline void SetAxesColor( const COLOR4D& aAxesColor ) { m_axesColor = aAxesColor; } /** * Enable drawing the axes. */ inline void SetAxesEnabled( bool aAxesEnabled ) { m_axesEnabled = aAxesEnabled; } /** * Draw every tick line wider. * * @param aInterval increase the width of every aInterval line, if 0 do not use this feature. */ inline void SetCoarseGrid( int aInterval ) { m_gridTick = aInterval; } /** * Get the grid line width. * * @return the grid line width */ inline float GetGridLineWidth() const { return m_gridLineWidth; } ///< Draw the grid virtual void DrawGrid() {}; /** * For a given point it returns the nearest point belonging to the grid in world coordinates. * * @param aPoint is the point for which the grid point is searched. * @return The nearest grid point in world coordinates. */ VECTOR2D GetGridPoint( const VECTOR2D& aPoint ) const; /** * Compute the point position in world coordinates from given screen coordinates. * * @param aPoint the point position in screen coordinates. * @return the point position in world coordinates. */ inline VECTOR2D ToWorld( const VECTOR2D& aPoint ) const { return VECTOR2D( m_screenWorldMatrix * aPoint ); } /** * Compute the point position in screen coordinates from given world coordinates. * * @param aPoint the point position in world coordinates. * @return the point position in screen coordinates. */ inline VECTOR2D ToScreen( const VECTOR2D& aPoint ) const { return VECTOR2D( m_worldScreenMatrix * aPoint ); } /** * Set the cursor in the native panel. * * @param aCursor is the cursor to use in the native panel * @return true if the cursor was updated, false if the cursor given was already set */ virtual bool SetNativeCursorStyle( KICURSOR aCursor ); /** * Enable/disable cursor. * * @param aCursorEnabled is true if the cursor should be drawn, else false. */ inline void SetCursorEnabled( bool aCursorEnabled ) { m_isCursorEnabled = aCursorEnabled; } /** * Return information about cursor visibility. * * @return True if cursor is visible. */ bool IsCursorEnabled() const { return m_isCursorEnabled || m_forceDisplayCursor; } /** * Set the cursor color. * * @param aCursorColor is the color of the cursor. */ inline void SetCursorColor( const COLOR4D& aCursorColor ) { m_cursorColor = aCursorColor; } /** * Draw the cursor. * * @param aCursorPosition is the cursor position in screen coordinates. */ virtual void DrawCursor( const VECTOR2D& aCursorPosition ) {}; /** * Change the current depth to deeper, so it is possible to draw objects right beneath * other. */ inline void AdvanceDepth() { m_layerDepth -= 0.05; } /** * Store current drawing depth on the depth stack. */ inline void PushDepth() { m_depthStack.push( m_layerDepth ); } /** * Restore previously stored drawing depth for the depth stack. */ inline void PopDepth() { m_layerDepth = m_depthStack.top(); m_depthStack.pop(); } virtual void EnableDepthTest( bool aEnabled = false ) {}; /** * Checks the state of the context lock * @return True if the context is currently locked */ virtual bool IsContextLocked() { return false; } /// Use GAL_CONTEXT_LOCKER RAII object unless you know what you're doing. virtual void LockContext( int aClientCookie ) {} virtual void UnlockContext( int aClientCookie ) {} /// Start/end drawing functions, draw calls can be only made in between the calls /// to BeginDrawing()/EndDrawing(). Normally you should create a GAL_DRAWING_CONTEXT RAII /// object, but I'm leaving these functions public for more precise (i.e. timing/profiling) /// control of the drawing process - Tom /// Begin the drawing, needs to be called for every new frame. /// Use GAL_DRAWING_CONTEXT RAII object unless you know what you're doing. virtual void BeginDrawing() {}; /// End the drawing, needs to be called for every new frame. /// Use GAL_DRAWING_CONTEXT RAII object unless you know what you're doing. virtual void EndDrawing() {}; protected: /// Enable item update mode. /// Private: use GAL_UPDATE_CONTEXT RAII object virtual void beginUpdate() {} /// Disable item update mode. virtual void endUpdate() {} /// Compute the scaling factor for the world->screen matrix inline void computeWorldScale() { m_worldScale = m_screenDPI * m_worldUnitLength * m_zoomFactor; } /** * compute minimum grid spacing from the grid settings * * @return the minimum spacing to use for drawing the grid */ double computeMinGridSpacing() const; /// Possible depth range static const int MIN_DEPTH; static const int MAX_DEPTH; /// Depth level on which the grid is drawn static const int GRID_DEPTH; /** * Get the actual cursor color to draw */ COLOR4D getCursorColor() const; // --------------- // Settings observer interface // --------------- /** * Handler for observer settings changes. */ void OnGalDisplayOptionsChanged( const GAL_DISPLAY_OPTIONS& aOptions ) override; /** * Handle updating display options. * * Derived classes should call up to this to set base-class methods. * * @return true if the new settings changed something. Derived classes can use this * information to refresh themselves */ virtual bool updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions ); GAL_DISPLAY_OPTIONS& m_options; UTIL::LINK m_observerLink; std::stack m_depthStack; ///< Stored depth values VECTOR2I m_screenSize; ///< Screen size in screen coordinates double m_worldUnitLength; ///< The unit length of the world coordinates [inch] double m_screenDPI; ///< The dots per inch of the screen VECTOR2D m_lookAtPoint; ///< Point to be looked at in world space double m_zoomFactor; ///< The zoom factor double m_rotation; ///< Rotation transformation (radians) MATRIX3x3D m_worldScreenMatrix; ///< World transformation MATRIX3x3D m_screenWorldMatrix; ///< Screen transformation double m_worldScale; ///< The scale factor world->screen bool m_globalFlipX; ///< Flag for X axis flipping bool m_globalFlipY; ///< Flag for Y axis flipping float m_lineWidth; ///< The line width bool m_isFillEnabled; ///< Is filling of graphic objects enabled ? bool m_isStrokeEnabled; ///< Are the outlines stroked ? COLOR4D m_fillColor; ///< The fill color COLOR4D m_strokeColor; ///< The color of the outlines COLOR4D m_clearColor; double m_layerDepth; ///< The actual layer depth VECTOR2D m_depthRange; ///< Range of the depth // Grid settings bool m_gridVisibility; ///< Should the grid be shown GRID_STYLE m_gridStyle; ///< Grid display style VECTOR2D m_gridSize; ///< The grid size VECTOR2D m_gridOrigin; ///< The grid origin VECTOR2D m_gridOffset; ///< The grid offset to compensate cursor position COLOR4D m_gridColor; ///< Color of the grid COLOR4D m_axesColor; ///< Color of the axes bool m_axesEnabled; ///< Should the axes be drawn int m_gridTick; ///< Every tick line gets the double width float m_gridLineWidth; ///< Line width of the grid int m_gridMinSpacing; ///< Minimum screen size of the grid (pixels) ///< below which the grid is not drawn // Cursor settings bool m_isCursorEnabled; ///< Is the cursor enabled? bool m_forceDisplayCursor; ///< Always show cursor COLOR4D m_cursorColor; ///< Cursor color bool m_fullscreenCursor; ///< Shape of the cursor (fullscreen or small cross) VECTOR2D m_cursorPosition; ///< Current cursor position (world coordinates) KICURSOR m_currentNativeCursor; ///< Current cursor private: TEXT_ATTRIBUTES m_attributes; }; class GAL_CONTEXT_LOCKER { public: GAL_CONTEXT_LOCKER( GAL* aGal ) : m_gal( aGal ) { m_cookie = rand(); m_gal->LockContext( m_cookie ); } ~GAL_CONTEXT_LOCKER() { m_gal->UnlockContext( m_cookie ); } protected: GAL* m_gal; int m_cookie; }; class GAL_UPDATE_CONTEXT : public GAL_CONTEXT_LOCKER { public: GAL_UPDATE_CONTEXT( GAL* aGal ) : GAL_CONTEXT_LOCKER( aGal ) { m_gal->beginUpdate(); } ~GAL_UPDATE_CONTEXT() { m_gal->endUpdate(); } }; class GAL_DRAWING_CONTEXT : public GAL_CONTEXT_LOCKER { public: GAL_DRAWING_CONTEXT( GAL* aGal ) : GAL_CONTEXT_LOCKER( aGal ) { m_gal->BeginDrawing(); } ~GAL_DRAWING_CONTEXT() noexcept( false ) { m_gal->EndDrawing(); } }; }; // namespace KIGFX #endif /* GRAPHICSABSTRACTIONLAYER_H_ */