champlain-error-tile-renderer.c 7.97 KB
Newer Older
1
/*
Jiří Techet's avatar
Jiří Techet committed
2
 * Copyright (C) 2010-2013 Jiri Techet <techet@gmail.com>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

Jiří Techet's avatar
Jiří Techet committed
19 20 21 22 23 24 25 26
/**
 * SECTION:champlain-error-tile-renderer
 * @short_description: A renderer that renders error tiles independently of input data
 *
 * #ChamplainErrorTileRenderer always renders error tiles (tiles that indicate that the real tile could
 * not be loaded) no matter what input data is used.
 */

27 28 29 30 31
#include "champlain-error-tile-renderer.h"
#include <gdk/gdk.h>

struct _ChamplainErrorTileRendererPrivate
{
32
  ClutterContent *error_canvas;
33 34 35
  guint tile_size;
};

36 37
G_DEFINE_TYPE_WITH_PRIVATE (ChamplainErrorTileRenderer, champlain_error_tile_renderer, CHAMPLAIN_TYPE_RENDERER)

38 39 40 41 42 43 44 45
enum
{
  PROP_0,
  PROP_TILE_SIZE
};


static void set_data (ChamplainRenderer *renderer,
46
    const guint8 *data,
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
    guint size);
static void render (ChamplainRenderer *renderer,
    ChamplainTile *tile);


static void
champlain_error_tile_renderer_get_property (GObject *object,
    guint property_id,
    GValue *value,
    GParamSpec *pspec)
{
  ChamplainErrorTileRenderer *renderer = CHAMPLAIN_ERROR_TILE_RENDERER (object);

  switch (property_id)
    {
    case PROP_TILE_SIZE:
      g_value_set_uint (value, champlain_error_tile_renderer_get_tile_size (renderer));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}


static void
champlain_error_tile_renderer_set_property (GObject *object,
    guint property_id,
    const GValue *value,
    GParamSpec *pspec)
{
  ChamplainErrorTileRenderer *renderer = CHAMPLAIN_ERROR_TILE_RENDERER (object);

  switch (property_id)
    {
    case PROP_TILE_SIZE:
      champlain_error_tile_renderer_set_tile_size (renderer, g_value_get_uint (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}


static void
champlain_error_tile_renderer_dispose (GObject *object)
{
  ChamplainErrorTileRendererPrivate *priv = CHAMPLAIN_ERROR_TILE_RENDERER (object)->priv;

97
  if (priv->error_canvas)
98
    {
99 100
      g_object_unref (priv->error_canvas);
      priv->error_canvas = NULL;
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    }

  G_OBJECT_CLASS (champlain_error_tile_renderer_parent_class)->dispose (object);
}


static void
champlain_error_tile_renderer_finalize (GObject *object)
{
  G_OBJECT_CLASS (champlain_error_tile_renderer_parent_class)->finalize (object);
}


static void
champlain_error_tile_renderer_class_init (ChamplainErrorTileRendererClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  ChamplainRendererClass *renderer_class = CHAMPLAIN_RENDERER_CLASS (klass);

  object_class->get_property = champlain_error_tile_renderer_get_property;
  object_class->set_property = champlain_error_tile_renderer_set_property;
  object_class->finalize = champlain_error_tile_renderer_finalize;
  object_class->dispose = champlain_error_tile_renderer_dispose;

Jiří Techet's avatar
Jiří Techet committed
125 126 127 128 129 130 131
  /**
   * ChamplainErrorTileRenderer:tile-size:
   *
   * The size of the rendered tile.
   *
   * Since: 0.8
   */
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
  g_object_class_install_property (object_class,
      PROP_TILE_SIZE,
      g_param_spec_uint ("tile-size",
          "Tile Size",
          "The size of the rendered tile",
          0,
          G_MAXINT,
          256,
          G_PARAM_READWRITE));

  renderer_class->set_data = set_data;
  renderer_class->render = render;
}


static void
champlain_error_tile_renderer_init (ChamplainErrorTileRenderer *self)
{
150
  ChamplainErrorTileRendererPrivate *priv = champlain_error_tile_renderer_get_instance_private (self);
151 152 153

  self->priv = priv;

154
  priv->error_canvas = NULL;
155 156 157
}


Jiří Techet's avatar
Jiří Techet committed
158 159 160 161 162 163 164 165 166 167
/**
 * champlain_error_tile_renderer_new:
 * @tile_size: the size of the rendered error tile
 *
 * Constructor of a #ChamplainErrorTileRenderer.
 *
 * Returns: a constructed #ChamplainErrorTileRenderer
 *
 * Since: 0.8
 */
168 169 170
ChamplainErrorTileRenderer *
champlain_error_tile_renderer_new (guint tile_size)
{
171 172 173
  return g_object_new (CHAMPLAIN_TYPE_ERROR_TILE_RENDERER, 
      "tile-size", tile_size, 
      NULL);
174 175 176 177
}


static void
178
set_data (ChamplainRenderer *renderer, const guint8 *data, guint size)
179
{
Jiří Techet's avatar
Jiří Techet committed
180
  /* always render the error tile no matter what data is set */
181 182 183
}


184 185 186 187
static gboolean
redraw_tile (ClutterCanvas *canvas,
    cairo_t *cr,
    gint w,
188 189
    gint h,
    ChamplainTile *tile)
190 191 192 193
{
  cairo_pattern_t *pat;
  gint size = w;
  
194 195
  champlain_exportable_set_surface (CHAMPLAIN_EXPORTABLE (tile), cairo_get_target (cr));

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
  /* draw a linear gray to white pattern */
  pat = cairo_pattern_create_linear (size / 2.0, 0.0, size, size / 2.0);
  cairo_pattern_add_color_stop_rgb (pat, 0, 0.686, 0.686, 0.686);
  cairo_pattern_add_color_stop_rgb (pat, 1, 0.925, 0.925, 0.925);
  cairo_set_source (cr, pat);
  cairo_rectangle (cr, 0, 0, size, size);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* draw the red cross */
  cairo_set_source_rgb (cr, 0.424, 0.078, 0.078);
  cairo_set_line_width (cr, 14.0);
  cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
  cairo_move_to (cr, 24, 24);
  cairo_line_to (cr, 50, 50);
  cairo_move_to (cr, 50, 24);
  cairo_line_to (cr, 24, 50);
  cairo_stroke (cr);
215
  
216 217 218 219
  return TRUE;
}


220 221 222 223 224 225 226 227
static void
render (ChamplainRenderer *renderer, ChamplainTile *tile)
{
  g_return_if_fail (CHAMPLAIN_IS_ERROR_TILE_RENDERER (renderer));
  g_return_if_fail (CHAMPLAIN_IS_TILE (tile));

  ChamplainErrorTileRenderer *error_renderer = CHAMPLAIN_ERROR_TILE_RENDERER (renderer);
  ChamplainErrorTileRendererPrivate *priv = error_renderer->priv;
228
  ClutterActor *actor;
229 230 231
  gpointer data = NULL;
  guint size = 0;
  gboolean error = FALSE;
232 233 234 235

  if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADED)
    {
      /* cache is just validating tile - don't generate error tile in this case - instead use what we have */
236
      g_signal_emit_by_name (tile, "render-complete", data, size, error);
237 238 239 240 241
      return;
    }

  size = champlain_error_tile_renderer_get_tile_size (error_renderer);

242
  if (!priv->error_canvas)
243
    {
244 245
      priv->error_canvas = clutter_canvas_new ();
      clutter_canvas_set_size (CLUTTER_CANVAS (priv->error_canvas), size, size);
246
      g_signal_connect (priv->error_canvas, "draw", G_CALLBACK (redraw_tile), tile);
247
      clutter_content_invalidate (priv->error_canvas);
248 249
    }

250 251 252
  actor = clutter_actor_new ();
  clutter_actor_set_size (actor, size, size);
  clutter_actor_set_content (actor, priv->error_canvas);
253 254 255
  /* has to be set for proper opacity */
  clutter_actor_set_offscreen_redirect (actor, CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY);

256
  champlain_tile_set_content (tile, actor);
257
  g_signal_emit_by_name (tile, "render-complete", data, size, error);
258 259 260
}


Jiří Techet's avatar
Jiří Techet committed
261 262 263 264 265 266 267 268 269
/**
 * champlain_error_tile_renderer_set_tile_size:
 * @renderer: a #ChamplainErrorTileRenderer
 * @size: the size of the rendered error tiles
 *
 * Sets the size of the rendered error tile.
 *
 * Since: 0.8
 */
270 271 272 273 274 275 276 277 278 279 280 281
void
champlain_error_tile_renderer_set_tile_size (ChamplainErrorTileRenderer *renderer,
    guint size)
{
  g_return_if_fail (CHAMPLAIN_IS_ERROR_TILE_RENDERER (renderer));

  renderer->priv->tile_size = size;

  g_object_notify (G_OBJECT (renderer), "tile-size");
}


Jiří Techet's avatar
Jiří Techet committed
282 283 284 285 286 287 288 289 290 291
/**
 * champlain_error_tile_renderer_get_tile_size:
 * @renderer: a #ChamplainErrorTileRenderer
 *
 * Gets the size of the rendered error tiles.
 *
 * Returns: the size of the rendered error tiles
 *
 * Since: 0.8
 */
292 293 294 295 296 297 298
guint
champlain_error_tile_renderer_get_tile_size (ChamplainErrorTileRenderer *renderer)
{
  g_return_val_if_fail (CHAMPLAIN_IS_ERROR_TILE_RENDERER (renderer), 0);

  return renderer->priv->tile_size;
}