1 /* 2 * RGraphicsPlotManager.hpp 3 * 4 * Copyright (C) 2021 by RStudio, PBC 5 * 6 * Unless you have received this program directly from RStudio pursuant 7 * to the terms of a commercial license agreement with RStudio, then 8 * this program is licensed to you under the terms of version 3 of the 9 * GNU Affero General Public License. This program is distributed WITHOUT 10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, 11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the 12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. 13 * 14 */ 15 16 #ifndef R_SESSION_GRAPHICS_PLOT_MANAGER_HPP 17 #define R_SESSION_GRAPHICS_PLOT_MANAGER_HPP 18 19 #include <string> 20 #include <vector> 21 22 #include <boost/utility.hpp> 23 #include <boost/shared_ptr.hpp> 24 #include <boost/function.hpp> 25 #include <boost/regex.hpp> 26 #include <boost/circular_buffer.hpp> 27 28 #include <core/BoostSignals.hpp> 29 #include <shared_core/Error.hpp> 30 #include <shared_core/FilePath.hpp> 31 32 #include <r/session/RGraphics.hpp> 33 34 #include "RGraphicsTypes.hpp" 35 #include "RGraphicsPlot.hpp" 36 37 namespace rstudio { 38 namespace r { 39 namespace session { 40 namespace graphics { 41 42 // singleton 43 class PlotManager; 44 PlotManager& plotManager(); 45 46 struct GraphicsDeviceEvents 47 { 48 RSTUDIO_BOOST_SIGNAL<void (SEXP)> onNewPage; 49 RSTUDIO_BOOST_SIGNAL<void ()> onDrawing; 50 RSTUDIO_BOOST_SIGNAL<void ()> onResized; 51 RSTUDIO_BOOST_SIGNAL<void ()> onClosed; 52 }; 53 54 class PlotManipulatorManager; 55 56 class PlotManager : boost::noncopyable, public r::session::graphics::Display 57 { 58 private: 59 PlotManager(); 60 friend PlotManager& plotManager(); 61 62 public: ~PlotManager()63 virtual ~PlotManager() {} 64 65 core::Error initialize(const core::FilePath& graphicsPath, 66 const GraphicsDeviceFunctions& graphicsDevice, 67 GraphicsDeviceEvents* pEvents); 68 69 // plot list 70 virtual int plotCount() const; 71 virtual core::Error plotImageFilename(int index, 72 std::string* pImageFilename) const; 73 virtual int activePlotIndex() const; 74 virtual core::Error setActivePlot(int index); 75 virtual core::Error removePlot(int index); 76 77 // actions on active plot 78 virtual core::Error savePlotAsImage(const core::FilePath& filePath, 79 const std::string& format, 80 int widthPx, 81 int heightPx, 82 bool useDevicePixelRatio = false); 83 84 virtual core::Error savePlotAsImage(const core::FilePath& filePath, 85 const std::string& format, 86 int widthPx, 87 int heightPx, 88 double devicePixelRatio); 89 90 virtual core::Error savePlotAsPdf(const core::FilePath& filePath, 91 double widthInches, 92 double heightInches, 93 bool useCairoPdf); 94 95 virtual core::Error savePlotAsMetafile(const core::FilePath& filePath, 96 int widthPx, 97 int heightPx); 98 99 // display 100 virtual bool hasOutput() const; 101 virtual bool hasChanges() const; 102 virtual bool isActiveDevice() const; 103 virtual boost::posix_time::ptime lastChange() const; 104 virtual void render(boost::function<void(DisplayState)> outputFunction); 105 virtual std::string imageFilename() const; 106 virtual void refresh(); 107 108 // retrieve image path based on filename 109 virtual core::FilePath imagePath(const std::string& imageFilename) const; 110 111 virtual void clear(); 112 113 virtual RSTUDIO_BOOST_SIGNAL<void ()>& onShowManipulator(); 114 virtual void setPlotManipulatorValues(const core::json::Object& values); 115 virtual void manipulatorPlotClicked(int x, int y); 116 117 virtual void onBeforeExecute(); 118 119 // manipulate persistent state 120 core::Error savePlotsState(); 121 core::Error restorePlotsState(); 122 123 // fully serialize and deserialize to an external directory 124 core::Error serialize(const core::FilePath& saveToPath); 125 core::Error deserialize(const core::FilePath& restoreFromPath); 126 127 private: 128 129 // make plot manipulator manager a friend 130 friend class PlotManipulatorManager; 131 132 // typedefs 133 typedef boost::shared_ptr<Plot> PtrPlot; 134 135 // device events 136 void onDeviceNewPage(SEXP previousPageSnapshot); 137 void onDeviceDrawing(); 138 void onDeviceResized(); 139 void onDeviceClosed(); 140 141 // active plot 142 Plot& activePlot() const; 143 bool isValidPlotIndex(int index) const; 144 bool hasPlot() const; 145 146 // set change flag 147 void setDisplayHasChanges(bool hasChanges); 148 149 // invalidate the active plot 150 void invalidateActivePlot(); 151 152 // render active plot to display (used in setActivePlot and onSessionResume) 153 void renderActivePlotToDisplay(); 154 155 // render active plot file file 156 core::Error savePlotAsFile(const boost::function<core::Error()>& 157 deviceCreationFunction); 158 core::Error savePlotAsFile(const std::string& fileDeviceCreationCode); 159 160 core::Error savePlotAsBitmapFile(const core::FilePath& targetPath, 161 const std::string& bitmapFileType, 162 int width, 163 int height, 164 double pixelRatio); 165 166 core::Error savePlotAsSvg(const core::FilePath& targetPath, 167 int width, 168 int height); 169 170 core::Error savePlotAsPostscript(const core::FilePath& targetPath, 171 int width, 172 int height); 173 174 175 // error helpers 176 core::Error plotIndexError(int index, const core::ErrorLocation& location) 177 const; 178 179 std::string emptyImageFilename() const; 180 181 private: 182 friend class SuppressDeviceEventsScope; 183 184 // storage paths 185 core::FilePath plotsStateFile_; 186 core::FilePath graphicsPath_; 187 188 // interface to graphics device 189 GraphicsDeviceFunctions graphicsDevice_; 190 191 // state 192 bool displayHasChanges_; 193 boost::posix_time::ptime lastChange_; 194 bool suppressDeviceEvents_; 195 196 int activePlot_; 197 boost::circular_buffer<PtrPlot> plots_; 198 199 boost::regex plotInfoRegex_; 200 }; 201 202 class SuppressDeviceEventsScope 203 { 204 public: SuppressDeviceEventsScope(PlotManager & plotManager)205 SuppressDeviceEventsScope(PlotManager& plotManager) 206 : plotManager_(plotManager) 207 { 208 plotManager_.suppressDeviceEvents_ = true; 209 } 210 ~SuppressDeviceEventsScope()211 virtual ~SuppressDeviceEventsScope() 212 { 213 plotManager_.suppressDeviceEvents_ = false; 214 } 215 private: 216 PlotManager& plotManager_; 217 }; 218 219 220 } // namespace graphics 221 } // namespace session 222 } // namespace r 223 } // namespace rstudio 224 225 #endif // R_SESSION_GRAPHICS_PLOT_MANAGER_HPP 226 227