Dillo v3.1.1-14-g8f67d6e0
Loading...
Searching...
No Matches
image.cc
Go to the documentation of this file.
1/*
2 * Dillo Widget
3 *
4 * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21
22#include "image.hh"
23#include "../lout/msg.h"
24#include "../lout/misc.hh"
25#include "../lout/debug.hh"
26
27namespace dw {
28
29using namespace lout;
30
32{
33 shapesAndLinks = new container::typed::List <ShapeAndLink> (true);
34 defaultLink = -1;
35}
36
38{
39 delete shapesAndLinks;
40}
41
43 int x, int y)
44{
45 container::typed::Iterator <ShapeAndLink> it;
46
47 for (it = shapesAndLinks->iterator (); it.hasNext (); ) {
48 ShapeAndLink *shapeAndLink = it.getNext ();
49
50 shapeAndLink->shape->draw(view, style, x, y);
51 }
52}
53
55 ShapeAndLink *shapeAndLink = new ShapeAndLink ();
56 shapeAndLink->shape = shape;
57 shapeAndLink->link = link;
58 shapesAndLinks->append (shapeAndLink);
59}
60
62 container::typed::Iterator <ShapeAndLink> it;
63 int link = defaultLink;
64
65 for (it = shapesAndLinks->iterator (); it.hasNext (); ) {
66 ShapeAndLink *shapeAndLink = it.getNext ();
67
68 if (shapeAndLink->shape->isPointWithin (x, y)) {
69 link = shapeAndLink->link;
70 break;
71 }
72 }
73
74 return link;
75}
76
78{
79 imageMaps = new container::typed::HashTable <object::Object, ImageMap>
80 (true, true);
81 currentMap = NULL;
82}
83
88
97{
98 currentMap = new ImageMap ();
99 imageMaps->put (key, currentMap);
100}
101
109{
110 currentMap->add (shape, link);
111}
112
120
122 core::style::Style *style, int x, int y)
123{
124 ImageMap *map = imageMaps->get (key);
125
126 if (map)
127 map->draw(view, style, x, y);
128}
129
130int ImageMapsList::link (object::Object *key, int x, int y)
131{
132 int link = -1;
133 ImageMap *map = imageMaps->get (key);
134
135 if (map)
136 link = map->link (x, y);
137
138 return link;
139}
140
141// ----------------------------------------------------------------------
142
143int Image::CLASS_ID = -1;
144
145Image::Image(const char *altText)
146{
147 DBG_OBJ_CREATE ("dw::Image");
148 registerName ("dw::Image", &CLASS_ID);
149 this->altText = altText ? strdup (altText) : NULL;
150 altTextWidth = -1; // not yet calculated
151 buffer = NULL;
152 bufWidth = bufHeight = -1;
153 clicking = false;
154 currLink = -1;
155 mapList = NULL;
156 mapKey = NULL;
157 isMap = false;
158
159 DBG_OBJ_SET_NUM ("bufWidth", bufWidth);
160 DBG_OBJ_SET_NUM ("bufHeight", bufHeight);
161}
162
164{
165 if (altText)
166 free(altText);
167 if (buffer)
168 buffer->unref ();
169 if (mapKey)
170 delete mapKey;
171
173}
174
176{
177 DBG_OBJ_ENTER0 ("resize", 0, "sizeRequestImpl");
178
179 if (buffer) {
180 requisition->width = buffer->getRootWidth ();
181 requisition->ascent = buffer->getRootHeight ();
182 requisition->descent = 0;
183 } else {
184 if (altText && altText[0]) {
185 if (altTextWidth == -1)
186 altTextWidth =
187 layout->textWidth (getStyle()->font, altText, strlen (altText));
188
189 requisition->width = altTextWidth;
190 requisition->ascent = getStyle()->font->ascent;
191 requisition->descent = getStyle()->font->descent;
192 } else {
193 requisition->width = 0;
194 requisition->ascent = 0;
195 requisition->descent = 0;
196 }
197 }
198
199 requisition->width += boxDiffWidth ();
200 requisition->ascent += boxOffsetY ();
201 requisition->descent += boxRestHeight ();
202
203 correctRequisition (requisition, core::splitHeightPreserveDescent, true,
204 true);
205
206 if (buffer) {
207 // If one dimension is set, preserve the aspect ratio (without
208 // extraSpace/margin/border/padding). Notice that
209 // requisition->descent could have been changed in
210 // core::splitHeightPreserveDescent, so we do not make any
211 // assumtions here about it (and requisition->ascent).
212
213 // TODO Check again possible overflows. (Aren't buffer
214 // dimensions limited to 2^15?)
215
216 bool widthSpecified = getStyle()->width != core::style::LENGTH_AUTO ||
217 getStyle()->minWidth != core::style::LENGTH_AUTO ||
218 getStyle()->maxWidth != core::style::LENGTH_AUTO;
219 bool heightSpecified = getStyle()->height != core::style::LENGTH_AUTO ||
220 getStyle()->minHeight != core::style::LENGTH_AUTO ||
221 getStyle()->maxHeight != core::style::LENGTH_AUTO;
222
223 if (!widthSpecified && heightSpecified)
224 requisition->width =
225 (requisition->ascent + requisition->descent - boxDiffHeight ())
226 * buffer->getRootWidth () / buffer->getRootHeight ()
227 + boxDiffWidth ();
228 else if (widthSpecified && !heightSpecified) {
229 requisition->ascent = (requisition->width + boxDiffWidth ())
230 * buffer->getRootHeight () / buffer->getRootWidth ()
231 + boxOffsetY ();
232 requisition->descent = boxRestHeight ();
233 }
234 }
235
236 DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
237 requisition->width, requisition->ascent, requisition->descent);
238 DBG_OBJ_LEAVE ();
239}
240
242{
243 int contentWidth;
244 if (buffer)
245 contentWidth = buffer->getRootWidth ();
246 else {
247 if (altText && altText[0]) {
248 if (altTextWidth == -1)
249 altTextWidth =
250 layout->textWidth (getStyle()->font, altText, strlen (altText));
251 contentWidth = altTextWidth;
252 } else
253 contentWidth = 0;
254 }
255
256 int width = contentWidth + boxDiffWidth ();
257
258 // With percentage width, the image may be narrower than the buffer.
259 extremes->minWidth =
260 core::style::isPerLength (getStyle()->width) ? boxDiffWidth () : width;
261
262 // (We ignore the same effect for the maximal width.)
263 extremes->maxWidth = width;
264
265 extremes->minWidthIntrinsic = extremes->minWidth;
266 extremes->maxWidthIntrinsic = extremes->maxWidth;
267
268 correctExtremes (extremes, false);
269
270 extremes->adjustmentWidth =
271 misc::min (extremes->minWidthIntrinsic, extremes->minWidth);
272}
273
275{
276 DBG_OBJ_ENTER ("resize", 0, "sizeAllocateImpl", "%d, %d; %d * (%d + %d)",
277 allocation->x, allocation->y, allocation->width,
278 allocation->ascent, allocation->descent);
279
280
281 int newBufWidth = allocation->width - boxDiffWidth ();
282 int newBufHeight =
283 allocation->ascent + allocation->descent - boxDiffHeight ();
284
285 if (buffer && newBufWidth > 0 && newBufHeight > 0 &&
286 // Save some time when size did not change:
287 (newBufWidth != bufWidth || newBufHeight != bufHeight)) {
288 DBG_OBJ_MSG ("resize", 1, "replacing buffer");
289
290 core::Imgbuf *oldBuffer = buffer;
291 buffer = oldBuffer->getScaledBuf (newBufWidth, newBufHeight);
292 oldBuffer->unref ();
293
294 bufWidth = newBufWidth;
295 bufHeight = newBufHeight;
296
297 DBG_OBJ_ASSOC_CHILD (this->buffer);
298 DBG_OBJ_SET_NUM ("bufWidth", bufWidth);
299 DBG_OBJ_SET_NUM ("bufHeight", bufHeight);
300 }
301
302 DBG_OBJ_LEAVE ();
303}
304
306{
307 DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
308 // Nothing to do.
309 DBG_OBJ_LEAVE ();
310}
311
313{
314 // BUG: this is wrong for image maps, but the cursor position is unknown.
315 currLink = getStyle()->x_link;
316
317 if (currLink != -1) {
318 (void) layout->emitLinkEnter (this, currLink, -1, -1, -1);
319 }
320 Widget::enterNotifyImpl(event);
321}
322
324{
325 clicking = false;
326
327 if (currLink != -1) {
328 currLink = -1;
329 (void) layout->emitLinkEnter (this, -1, -1, -1, -1);
330 }
331 Widget::leaveNotifyImpl(event);
332}
333
334/*
335 * Return the coordinate relative to the contents.
336 * If the event occurred in the surrounding box, return the value at the
337 * edge of the contents instead.
338 */
340{
341 int ret = event->xWidget - boxOffsetX();
342
343 ret = misc::min(getContentWidth(), misc::max(ret, 0));
344 return ret;
345}
346
348{
349 int ret = event->yWidget - boxOffsetY();
350
351 ret = misc::min(getContentHeight(), misc::max(ret, 0));
352 return ret;
353}
354
356{
357 if (mapList || isMap) {
358 int x = contentX(event);
359 int y = contentY(event);
360
361 if (mapList) {
362 /* client-side image map */
363 int newLink = mapList->link (mapKey, x, y);
364 if (newLink != currLink) {
365 currLink = newLink;
366 clicking = false;
367 /* \todo Using MAP/AREA styles would probably be best */
368 setCursor(newLink == -1 ? getStyle()->cursor :
370 (void) layout->emitLinkEnter (this, newLink, -1, -1, -1);
371 }
372 } else if (isMap && currLink != -1) {
373 /* server-side image map */
374 (void) layout->emitLinkEnter (this, currLink, -1, x, y);
375 }
376 }
377 return true;
378}
379
381{
382 bool ret = false;
383
384 currLink = mapList ? mapList->link(mapKey,contentX(event),contentY(event)) :
385 getStyle()->x_link;
386 if (event->button == 3){
387 (void)layout->emitLinkPress(this, currLink, getStyle()->x_img, -1, -1,
388 event);
389 ret = true;
390 } else if (event->button == 1 || currLink != -1){
391 clicking = true;
392 ret = true;
393 }
394 return ret;
395}
396
398{
399 currLink = mapList ? mapList->link(mapKey,contentX(event),contentY(event)) :
400 getStyle()->x_link;
401 if (clicking) {
402 int x = isMap ? contentX(event) : -1;
403 int y = isMap ? contentY(event) : -1;
404 clicking = false;
405 layout->emitLinkClick (this, currLink, getStyle()->x_img, x, y, event);
406 return true;
407 }
408 return false;
409}
410
412 core::DrawingContext *context)
413{
414 int dx, dy;
415 core::Rectangle content, intersection;
416
417 drawWidgetBox (view, area, false);
418
419 if (buffer) {
420 dx = boxOffsetX ();
421 dy = boxOffsetY ();
422 content.x = dx;
423 content.y = dy;
424 content.width = getContentWidth ();
425 content.height = getContentHeight ();
426
427 if (area->intersectsWith (&content, &intersection))
428 view->drawImage (buffer,
429 allocation.x + dx, allocation.y + dy,
430 intersection.x - dx, intersection.y - dy,
431 intersection.width, intersection.height);
432 } else {
433 core::View *clippingView;
434
435 if (altText && altText[0]) {
436 core::View *usedView = view;
437
438 clippingView = NULL;
439
440 if (altTextWidth == -1)
441 altTextWidth =
442 layout->textWidth (getStyle()->font, altText, strlen (altText));
443
444 if ((getContentWidth() < altTextWidth) ||
445 (getContentHeight() <
446 getStyle()->font->ascent + getStyle()->font->descent)) {
447 clippingView = usedView =
448 view->getClippingView (allocation.x + boxOffsetX (),
449 allocation.y + boxOffsetY (),
450 getContentWidth(),
451 getContentHeight());
452 }
453
454 usedView->drawSimpleWrappedText (getStyle()->font, getStyle()->color,
456 allocation.x + boxOffsetX (),
457 allocation.y + boxOffsetY (),
458 getContentWidth(), getContentHeight(), altText);
459
460 if (clippingView)
461 view->mergeClippingView (clippingView);
462 }
463 if (mapKey) {
464 clippingView = view->getClippingView (allocation.x + boxOffsetX (),
465 allocation.y + boxOffsetY (),
466 getContentWidth(),
467 getContentHeight());
468 mapList->drawMap(mapKey, clippingView, getStyle(),
469 allocation.x + boxOffsetX (),
470 allocation.y + boxOffsetY ());
471 view->mergeClippingView (clippingView);
472 }
473 }
474
476}
477
479{
480 //return new core::TextIterator (this, mask, atEnd, altText);
482 return new core::EmptyIterator (this, mask, atEnd);
483}
484
485void Image::setBuffer (core::Imgbuf *buffer, bool resize)
486{
487 core::Imgbuf *oldBuf = this->buffer;
488
489 if (wasAllocated () && needsResize () &&
490 getContentWidth () > 0 && getContentHeight () > 0) {
491 // Don't create a new buffer for the transition from alt text to img,
492 // and only scale when both dimensions are known.
493
494 bufWidth = getContentWidth ();
495 bufHeight = getContentHeight ();
496 this->buffer = buffer->getScaledBuf (bufWidth, bufHeight);
497 } else {
498 this->buffer = buffer;
499 bufWidth = buffer->getRootWidth ();
500 bufHeight = buffer->getRootHeight ();
501 buffer->ref ();
502 }
503 queueResize (0, true);
504
505 DBG_OBJ_ASSOC_CHILD (this->buffer);
506 DBG_OBJ_SET_NUM ("bufWidth", bufWidth);
507 DBG_OBJ_SET_NUM ("bufHeight", bufHeight);
508
509 if (oldBuf)
510 oldBuf->unref ();
511}
512
513void Image::drawRow (int row)
514{
515 core::Rectangle area;
516
517 assert (buffer != NULL);
518
519 buffer->getRowArea (row, &area);
520 if (area.width && area.height)
521 queueDrawArea (area.x + boxOffsetX (), area.y + boxOffsetY (), area.width,
522 area.height);
523}
524
526{
527 // Nothing to do; images are always drawn line by line.
528}
529
531{
532 // Could display an error.
533}
534
535
540{
541 isMap = true;
542}
543
544
553{
554 mapList = list;
555 if (mapKey && mapKey != key)
556 delete mapKey;
557 mapKey = key;
558}
559
560} // namespace dw
void setDefaultLink(int link)
Definition image.hh:44
void add(core::Shape *shape, int link)
Definition image.cc:54
int link(int x, int y)
Definition image.cc:61
void draw(core::View *view, core::style::Style *style, int x, int y)
Definition image.cc:42
lout::container::typed::List< ShapeAndLink > * shapesAndLinks
Definition image.hh:36
Represents a list of client-side image maps.
Definition image.hh:24
void drawMap(lout::object::Object *key, core::View *view, core::style::Style *style, int x, int y)
Definition image.cc:121
ImageMap * currentMap
Definition image.hh:50
void addShapeToCurrentMap(core::Shape *shape, int link)
Add a shape to the current map-.
Definition image.cc:108
void startNewMap(lout::object::Object *key)
Start a new map and make it the current one.
Definition image.cc:96
lout::container::typed::HashTable< lout::object::Object, ImageMap > * imageMaps
Definition image.hh:49
void setCurrentMapDefaultLink(int link)
Set default link for current map-.
Definition image.cc:116
int link(lout::object::Object *key, int x, int y)
Definition image.cc:130
void setIsMap()
Sets image as server side image map.
Definition image.cc:539
void setUseMap(ImageMapsList *list, Object *key)
Sets image as client side image map.
Definition image.cc:552
core::Iterator * iterator(core::Content::Type mask, bool atEnd)
Return an iterator for this widget.
Definition image.cc:478
int contentY(core::MousePositionEvent *event)
Definition image.cc:347
void finish()
Called, when all image data has been retrieved.
Definition image.cc:525
void drawRow(int row)
Called, when data from a row is available and has been copied into the image buffer.
Definition image.cc:513
Image(const char *altText)
Definition image.cc:145
void sizeAllocateImpl(core::Allocation *allocation)
See Sizes of Dillo Widgets.
Definition image.cc:274
bool buttonReleaseImpl(core::EventButton *event)
Definition image.cc:397
void sizeRequestSimpl(core::Requisition *requisition)
Simple variant, to be implemented by widgets with sizes not depending on positions.
Definition image.cc:175
static int CLASS_ID
Definition image.hh:152
void containerSizeChangedForChildren()
Definition image.cc:305
bool buttonPressImpl(core::EventButton *event)
Definition image.cc:380
void fatal()
Called, when there are problems with the retrieval of image data.
Definition image.cc:530
int contentX(core::MousePositionEvent *event)
Definition image.cc:339
void getExtremesSimpl(core::Extremes *extremes)
Simple variant, to be implemented by widgets with extremes not depending on positions.
Definition image.cc:241
void setBuffer(core::Imgbuf *buffer, bool resize=false)
Called, when an image buffer is attached.
Definition image.cc:485
void enterNotifyImpl(core::EventCrossing *event)
Definition image.cc:312
void leaveNotifyImpl(core::EventCrossing *event)
Definition image.cc:323
bool motionNotifyImpl(core::EventMotion *event)
Definition image.cc:355
void draw(core::View *view, core::Rectangle *area, core::DrawingContext *context)
Area is given in widget coordinates.
Definition image.cc:411
Set at the top when drawing.
Definition types.hh:295
This implementation of dw::core::Iterator can be used by widgets with no contents.
Definition iterator.hh:97
Represents a button press or release event.
Definition events.hh:58
Represents a enter or leave notify event.
Definition events.hh:75
Represents a mouse motion event.
Definition events.hh:68
The platform independent interface for image buffers.
Definition imgbuf.hh:162
virtual int getRootWidth()=0
virtual void ref()=0
virtual Imgbuf * getScaledBuf(int width, int height)=0
virtual void unref()=0
virtual int getRootHeight()=0
Iterators are used to iterate through the contents of a widget.
Definition iterator.hh:20
Base class for all mouse events related to a specific position.
Definition events.hh:49
dw::core::Shape implemtation for simple rectangles.
Definition types.hh:70
bool intersectsWith(Rectangle *otherRect, Rectangle *dest)
Return whether this rectangle and otherRect intersect.
Definition types.cc:53
Abstract interface for different shapes.
Definition types.hh:59
virtual bool isPointWithin(int x, int y)=0
virtual void draw(core::View *view, core::style::Style *style, int x, int y)=0
An interface to encapsulate platform dependent drawing.
Definition view.hh:17
virtual void mergeClippingView(View *clippingView)=0
virtual void drawImage(Imgbuf *imgbuf, int xRoot, int yRoot, int x, int y, int width, int height)=0
virtual void drawSimpleWrappedText(style::Font *font, style::Color *color, style::Color::Shading shading, int x, int y, int w, int h, const char *text)=0
virtual View * getClippingView(int x, int y, int width, int height)=0
This is the base class for many other classes, which defines very common virtual methods.
Definition object.hh:25
#define DBG_OBJ_ENTER0(aspect, prio, funname)
#define DBG_OBJ_DELETE()
#define DBG_OBJ_CREATE(klass)
#define DBG_OBJ_MSGF(aspect, prio, fmt,...)
#define DBG_OBJ_SET_NUM(var, val)
#define DBG_OBJ_MSG(aspect, prio, msg)
#define DBG_OBJ_ENTER(aspect, prio, funname, fmt,...)
#define DBG_OBJ_LEAVE()
#define DBG_OBJ_ASSOC_CHILD(child)
static Layout * layout
bool isPerLength(Length l)
Returns true if l is a percentage.
Definition style.hh:445
@ LENGTH_AUTO
Represents "auto" lengths.
Definition style.hh:494
void splitHeightPreserveDescent(int height, int *ascent, int *descent)
Definition widget.cc:2024
Dw is in this namespace, or sub namespaces of this one.
T min(T a, T b)
Definition misc.hh:19
T max(T a, T b)
Definition misc.hh:20
The DilloImage data-structure and methods.
Represents the allocation, i.e.
Definition types.hh:164