aboutsummaryrefslogtreecommitdiff
path: root/dw/image.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/image.cc')
-rw-r--r--dw/image.cc392
1 files changed, 392 insertions, 0 deletions
diff --git a/dw/image.cc b/dw/image.cc
new file mode 100644
index 00000000..499fc438
--- /dev/null
+++ b/dw/image.cc
@@ -0,0 +1,392 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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 3 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+
+#include "image.hh"
+#include "../lout/misc.hh"
+
+namespace dw {
+
+using namespace lout;
+
+ImageMapsList::ImageMap::ImageMap ()
+{
+ shapesAndLinks = new container::typed::List <ShapeAndLink> (true);
+ defaultLink = -1;
+}
+
+ImageMapsList::ImageMap::~ImageMap ()
+{
+ delete shapesAndLinks;
+}
+
+void ImageMapsList::ImageMap::add (core::Shape *shape, int link) {
+ ShapeAndLink *shapeAndLink = new ShapeAndLink ();
+ shapeAndLink->shape = shape;
+ shapeAndLink->link = link;
+ shapesAndLinks->append (shapeAndLink);
+}
+
+int ImageMapsList::ImageMap::link (int x, int y) {
+ container::typed::Iterator <ShapeAndLink> it;
+ int link = defaultLink;
+
+ for (it = shapesAndLinks->iterator (); it.hasNext (); ) {
+ ShapeAndLink *shapeAndLink = it.getNext ();
+
+ if (shapeAndLink->shape->isPointWithin (x, y)) {
+ link = shapeAndLink->link;
+ break;
+ }
+ }
+
+ return link;
+}
+
+ImageMapsList::ImageMapsList ()
+{
+ imageMaps = new container::typed::HashTable <object::Object, ImageMap>
+ (true, true);
+ currentMap = NULL;
+}
+
+ImageMapsList::~ImageMapsList ()
+{
+ delete imageMaps;
+}
+
+/**
+ * \brief Start a new map and make it the current one.
+ *
+ * This has to be called before dw::ImageMapsList::addShapeToCurrentMap.
+ * "key" is owned by the image map list, so a copy should be passed, when
+ * necessary.
+ */
+void ImageMapsList::startNewMap (object::Object *key)
+{
+ currentMap = new ImageMap ();
+ imageMaps->put (key, currentMap);
+}
+
+/**
+ * \brief Add a shape to the current map-
+ *
+ * "shape" is owned by the image map list, so a copy should be passed, when
+ * necessary.
+ */
+void ImageMapsList::addShapeToCurrentMap (core::Shape *shape, int link)
+{
+ currentMap->add (shape, link);
+}
+
+/**
+ * \brief Set default link for current map-
+ */
+void ImageMapsList::setCurrentMapDefaultLink (int link)
+{
+ currentMap->setDefaultLink (link);
+}
+
+int ImageMapsList::link (object::Object *key, int x, int y)
+{
+ int link = -1;
+ ImageMap *map = imageMaps->get (key);
+
+ if (map)
+ link = map->link (x, y);
+
+ return link;
+}
+
+// ----------------------------------------------------------------------
+
+int Image::CLASS_ID = -1;
+
+Image::Image(const char *altText)
+{
+ registerName ("dw::Image", &CLASS_ID);
+ this->altText = altText ? strdup (altText) : NULL;
+ altTextWidth = -1; // not yet calculated
+ buffer = NULL;
+ clicking = false;
+ currLink = -1;
+ mapList = NULL;
+ mapKey = NULL;
+ isMap = false;
+}
+
+Image::~Image()
+{
+ if (altText)
+ delete altText;
+ if (buffer)
+ buffer->unref ();
+}
+
+void Image::sizeRequestImpl (core::Requisition *requisition)
+{
+ if (buffer) {
+ requisition->width = buffer->getRootWidth ();
+ requisition->ascent = buffer->getRootHeight ();
+ requisition->descent = 0;
+ } else {
+ if(altText && altText[0]) {
+ if (altTextWidth == -1)
+ altTextWidth =
+ layout->textWidth (getStyle()->font, altText, strlen (altText));
+
+ requisition->width = altTextWidth;
+ requisition->ascent = getStyle()->font->ascent;
+ requisition->descent = getStyle()->font->descent;
+ } else {
+ requisition->width = 0;
+ requisition->ascent = 0;
+ requisition->descent = 0;
+ }
+ }
+
+ requisition->width += getStyle()->boxDiffWidth ();
+ requisition->ascent += getStyle()->boxOffsetY ();
+ requisition->descent += getStyle()->boxRestHeight ();
+}
+
+void Image::sizeAllocateImpl (core::Allocation *allocation)
+{
+ core::Imgbuf *oldBuffer;
+ int dx, dy;
+
+ /* if image is moved only */
+ if (allocation->width == this->allocation.width &&
+ allocation->ascent + allocation->descent == getHeight ())
+ return;
+
+ dx = getStyle()->boxDiffWidth ();
+ dy = getStyle()->boxDiffHeight ();
+#if 0
+ printf("boxDiffHeight = %d + %d, buffer=%p\n",
+ getStyle()->boxOffsetY(), getStyle()->boxRestHeight(), buffer);
+ printf("getContentWidth() = allocation.width - style->boxDiffWidth ()"
+ " = %d - %d = %d\n",
+ this->allocation.width, getStyle()->boxDiffWidth(),
+ this->allocation.width - getStyle()->boxDiffWidth());
+ printf("getContentHeight() = getHeight() - style->boxDiffHeight ()"
+ " = %d - %d = %d\n", this->getHeight(), getStyle()->boxDiffHeight(),
+ this->getHeight() - getStyle()->boxDiffHeight());
+#endif
+ if (buffer != NULL &&
+ /* It may be, that the image is allocated at zero content size. In this
+ * case, we simply wait. */
+ getContentWidth () > 0 && getContentHeight () > 0) {
+ oldBuffer = buffer;
+ buffer = oldBuffer->getScaledBuf (allocation->width - dx,
+ allocation->ascent
+ + allocation->descent - dy);
+ oldBuffer->unref ();
+ }
+}
+
+void Image::enterNotifyImpl (core::EventCrossing *event)
+{
+ // BUG: this is wrong for image maps, but the cursor position is unknown.
+ currLink = getStyle()->x_link;
+
+ if (currLink != -1) {
+ (void) emitLinkEnter (currLink, -1, -1, -1);
+ }
+}
+
+void Image::leaveNotifyImpl (core::EventCrossing *event)
+{
+ clicking = false;
+
+ if (currLink != -1) {
+ currLink = -1;
+ (void) emitLinkEnter (-1, -1, -1, -1);
+ }
+}
+
+bool Image::motionNotifyImpl (core::EventMotion *event)
+{
+ if (mapList) {
+ /* client-side image map */
+ int newLink = mapList->link (mapKey, event->xWidget, event->yWidget);
+ if (newLink != currLink) {
+ currLink = newLink;
+ clicking = false;
+ setCursor(newLink == -1 ? core::style::CURSOR_DEFAULT :
+ core::style::CURSOR_POINTER);
+ (void) emitLinkEnter (newLink, -1, -1, -1);
+ }
+ } else if (isMap && currLink != -1) {
+ /* server-side image map */
+ (void) emitLinkEnter (currLink, -1, event->xWidget, event->yWidget);
+ }
+ return true;
+}
+
+bool Image::buttonPressImpl (core::EventButton *event)
+{
+ bool ret = false;
+ currLink = mapList ? mapList->link (mapKey, event->xWidget, event->yWidget):
+ getStyle()->x_link;
+ if (event->button == 3){
+ (void)emitLinkPress(currLink, getStyle()->x_img, -1,-1,event);
+ ret = true;
+ } else if (event->button == 1 || currLink != -1){
+ clicking = true;
+ ret = true;
+ }
+ return ret;
+}
+
+bool Image::buttonReleaseImpl (core::EventButton *event)
+{
+ currLink = mapList ? mapList->link (mapKey, event->xWidget, event->yWidget):
+ getStyle()->x_link;
+ if (clicking) {
+ int x = isMap ? event->xWidget : -1;
+ int y = isMap ? event->yWidget : -1;
+ clicking = false;
+ emitLinkClick (currLink, getStyle()->x_img, x, y, event);
+ return true;
+ }
+ return false;
+}
+
+void Image::draw (core::View *view, core::Rectangle *area)
+{
+ int dx, dy;
+ core::Rectangle content, intersection;
+
+ drawWidgetBox (view, area, false);
+
+ if (buffer) {
+ dx = getStyle()->boxOffsetX ();
+ dy = getStyle()->boxOffsetY ();
+ content.x = dx;
+ content.y = dy;
+ content.width = getContentWidth ();
+ content.height = getContentHeight ();
+
+ if (area->intersectsWith (&content, &intersection))
+ view->drawImage (buffer,
+ allocation.x + dx, allocation.y + dy,
+ intersection.x - dx, intersection.y - dy,
+ intersection.width, intersection.height);
+ } else {
+ if(altText && altText[0]) {
+ if (altTextWidth == -1)
+ altTextWidth =
+ layout->textWidth (getStyle()->font, altText, strlen (altText));
+
+ core::View *clippingView = NULL, *usedView = view;
+ if (allocation.width < altTextWidth ||
+ allocation.ascent < getStyle()->font->ascent ||
+ allocation.descent < getStyle()->font->descent) {
+ clippingView = usedView =
+ view->getClippingView (allocation.x + getStyle()->boxOffsetX (),
+ allocation.y + getStyle()->boxOffsetY (),
+ allocation.width
+ - getStyle()->boxDiffWidth (),
+ allocation.ascent + allocation.descent
+ - getStyle()->boxDiffHeight ());
+ }
+
+ usedView->drawText (getStyle()->font, getStyle()->color,
+ core::style::Color::SHADING_NORMAL,
+ allocation.x + getStyle()->boxOffsetX (),
+ allocation.y + getStyle()->boxOffsetY ()
+ + getStyle()->font->ascent,
+ altText, strlen(altText));
+
+ if(clippingView)
+ view->mergeClippingView (clippingView);
+ }
+ }
+
+ /** todo: draw selection */
+}
+
+core::Iterator *Image::iterator (core::Content::Type mask, bool atEnd)
+{
+ //return new core::TextIterator (this, mask, atEnd, altText);
+ /** \bug Not implemented. */
+ return new core::EmptyIterator (this, mask, atEnd);
+}
+
+void Image::setBuffer (core::Imgbuf *buffer, bool resize)
+{
+ core::Imgbuf *oldBuf = this->buffer;
+
+ if (resize)
+ queueResize (0, true);
+
+ // If the image has not yet been allocated, or is allocated at zero
+ // content size, the first part is useless.
+ if (wasAllocated () && getContentWidth () > 0 && getContentHeight () > 0) {
+ this->buffer =
+ buffer->getScaledBuf (getContentWidth (), getContentHeight ());
+ } else {
+ this->buffer = buffer;
+ buffer->ref ();
+ }
+
+ if (oldBuf)
+ oldBuf->unref ();
+}
+
+void Image::drawRow (int row)
+{
+ core::Rectangle area;
+
+ assert (buffer != NULL);
+
+ buffer->getRowArea (row, &area);
+ if (area.width && area.height)
+ queueDrawArea (area.x + getStyle()->boxOffsetX (),
+ area.y + getStyle()->boxOffsetY (),
+ area.width, area.height);
+}
+
+
+/**
+ * \brief Sets image as server side image map.
+ */
+void Image::setIsMap ()
+{
+ isMap = true;
+}
+
+
+/**
+ * \brief Sets image as client side image map.
+ *
+ * "list" is not owned by the image, the caller has to free it. "key"
+ * is owned by the image, if it is used by the caller afterwards, a copy
+ * should be passed.
+ */
+void Image::setUseMap (ImageMapsList *list, object::Object *key)
+{
+ mapList = list;
+ mapKey = key;
+}
+
+} // namespace dw