]> git.lyx.org Git - lyx.git/blob - src/insets/render_graphic.C
Refactoring of renderer code to make inset code simpler.
[lyx.git] / src / insets / render_graphic.C
1 /**
2  * \file render_graphic.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "render_graphic.h"
14
15 #include "insets/inset.h"
16
17 #include "gettext.h"
18 #include "LColor.h"
19 #include "lyx_main.h"
20 #include "lyxrc.h"
21 #include "metricsinfo.h"
22
23 #include "frontends/font_metrics.h"
24 #include "frontends/Painter.h"
25
26 #include "graphics/GraphicsImage.h"
27
28 #include "support/filetools.h"
29
30 #include <boost/bind.hpp>
31
32 namespace graphics = lyx::graphics;
33
34 using lyx::support::AbsolutePath;
35 using lyx::support::OnlyFilename;
36
37 using std::string;
38 using std::auto_ptr;
39
40
41 RenderGraphic::RenderGraphic(InsetBase const * inset)
42         : checksum_(0)
43 {
44         loader_.connect(boost::bind(&LyX::updateInset,
45                                     boost::cref(LyX::cref()), inset));
46 }
47
48
49 RenderGraphic::RenderGraphic(RenderGraphic const & other,
50                              InsetBase const * inset)
51         : RenderBase(other),
52           loader_(other.loader_),
53           params_(other.params_),
54           checksum_(0)
55 {
56         loader_.connect(boost::bind(&LyX::updateInset,
57                                     boost::cref(LyX::cref()), inset));
58 }
59
60
61 auto_ptr<RenderBase> RenderGraphic::clone(InsetBase const * inset) const
62 {
63         return auto_ptr<RenderBase>(new RenderGraphic(*this, inset));
64 }
65
66
67 void RenderGraphic::update(graphics::Params const & params)
68 {
69         params_ = params;
70
71         if (!params_.filename.empty()) {
72                 BOOST_ASSERT(AbsolutePath(params_.filename));
73                 loader_.reset(params_.filename, params_);
74         }
75 }
76
77
78 bool RenderGraphic::hasFileChanged() const
79 {
80         unsigned long const new_checksum = loader_.checksum();
81         bool const file_has_changed = checksum_ != new_checksum;
82         if (file_has_changed)
83                 checksum_ = new_checksum;
84         return file_has_changed;
85 }
86
87
88 namespace {
89
90 bool displayGraphic(graphics::Params const & params)
91 {
92         return params.display != graphics::NoDisplay &&
93                 lyxrc.display_graphics != graphics::NoDisplay;
94 }
95         
96
97 string const statusMessage(graphics::Params const & params,
98                            graphics::ImageStatus status)
99 {
100         if (!displayGraphic(params))
101                 return _("Not shown.");
102
103         switch (status) {
104         case graphics::WaitingToLoad:
105                 return _("Not shown.");
106         case graphics::Loading:
107                 return _("Loading...");
108         case graphics::Converting:
109                 return _("Converting to loadable format...");
110         case graphics::Loaded:
111                 return _("Loaded into memory. Generating pixmap...");
112         case graphics::ScalingEtc:
113                 return _("Scaling etc...");
114         case graphics::Ready:
115                 return _("Ready to display");
116         case graphics::ErrorNoFile:
117                 return _("No file found!");
118         case graphics::ErrorConverting:
119                 return _("Error converting to loadable format");
120         case graphics::ErrorLoading:
121                 return _("Error loading file into memory");
122         case graphics::ErrorGeneratingPixmap:
123                 return _("Error generating the pixmap");
124         case graphics::ErrorUnknown:
125                 return _("No image");
126         }
127         return string();
128 }
129
130
131 bool readyToDisplay(graphics::Loader const & loader)
132 {
133         if (!loader.image() || loader.status() != graphics::Ready)
134                 return false;
135         return loader.image()->isDrawable();
136 }
137
138 } // namespace anon
139
140
141 void RenderGraphic::metrics(MetricsInfo & mi, Dimension & dim) const
142 {
143         bool image_ready = displayGraphic(params_) && readyToDisplay(loader_);
144
145         dim.asc = image_ready ? loader_.image()->getHeight() : 50;
146         dim.des = 0;
147
148         if (image_ready) {
149                 dim.wid = loader_.image()->getWidth() +
150                         2 * InsetOld::TEXT_TO_INSET_OFFSET;
151         } else {
152                 int font_width = 0;
153
154                 LyXFont msgFont(mi.base.font);
155                 msgFont.setFamily(LyXFont::SANS_FAMILY);
156
157                 string const justname = OnlyFilename(params_.filename);
158                 if (!justname.empty()) {
159                         msgFont.setSize(LyXFont::SIZE_FOOTNOTE);
160                         font_width = font_metrics::width(justname, msgFont);
161                 }
162
163                 string const msg = statusMessage(params_, loader_.status());
164                 if (!msg.empty()) {
165                         msgFont.setSize(LyXFont::SIZE_TINY);
166                         font_width = std::max(font_width,
167                                               font_metrics::width(msg, msgFont));
168                 }
169
170                 dim.wid = std::max(50, font_width + 15);
171         }
172
173         dim_ = dim;
174 }
175
176
177 void RenderGraphic::draw(PainterInfo & pi, int x, int y) const
178 {
179         if (displayGraphic(params_)) {
180                 if (loader_.status() == graphics::WaitingToLoad)
181                         loader_.startLoading();
182                 if (!loader_.monitoring())
183                         loader_.startMonitoring();
184         }
185
186         // This will draw the graphics. If the graphics has not been
187         // loaded yet, we draw just a rectangle.
188
189         if (displayGraphic(params_) && readyToDisplay(loader_)) {
190                 pi.pain.image(x + InsetOld::TEXT_TO_INSET_OFFSET,
191                               y - dim_.asc,
192                               dim_.wid - 2 * InsetOld::TEXT_TO_INSET_OFFSET,
193                               dim_.asc + dim_.des,
194                               *loader_.image());
195
196         } else {
197                 pi.pain.rectangle(x + InsetOld::TEXT_TO_INSET_OFFSET,
198                                   y - dim_.asc,
199                                   dim_.wid - 2 * InsetOld::TEXT_TO_INSET_OFFSET,
200                                   dim_.asc + dim_.des,
201                                   LColor::foreground);
202
203                 // Print the file name.
204                 LyXFont msgFont = pi.base.font;
205                 msgFont.setFamily(LyXFont::SANS_FAMILY);
206                 string const justname = OnlyFilename(params_.filename);
207
208                 if (!justname.empty()) {
209                         msgFont.setSize(LyXFont::SIZE_FOOTNOTE);
210                         pi.pain.text(x + InsetOld::TEXT_TO_INSET_OFFSET + 6,
211                                    y - font_metrics::maxAscent(msgFont) - 4,
212                                    justname, msgFont);
213                 }
214
215                 // Print the message.
216                 string const msg = statusMessage(params_, loader_.status());
217                 if (!msg.empty()) {
218                         msgFont.setSize(LyXFont::SIZE_TINY);
219                         pi.pain.text(x + InsetOld::TEXT_TO_INSET_OFFSET + 6,
220                                      y - 4, msg, msgFont);
221                 }
222         }
223 }