Back to index

unity  6.0.0
DashStyle.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2011 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Mirco Müller <mirco.mueller@canonical.com
00018  *              Neil Jagdish Patel <neil.patel@canonical.com>
00019  */
00020 
00021 #include "DashStyle.h"
00022 
00023 #include <string>
00024 #include <vector>
00025 #include <map>
00026 #include <cmath>
00027 
00028 #include <glib.h>
00029 #include <gdk/gdk.h>
00030 #include <gtk/gtk.h>
00031 #include <pango/pango.h>
00032 
00033 #include <NuxCore/Color.h>
00034 #include <NuxCore/Logger.h>
00035 #include <NuxGraphics/ImageSurface.h>
00036 #include <NuxGraphics/CairoGraphics.h>
00037 
00038 #include <Nux/PaintLayer.h>
00039 
00040 #include <UnityCore/GLibSignal.h>
00041 #include <UnityCore/GLibWrapper.h>
00042 
00043 #include "CairoTexture.h"
00044 #include "JSONParser.h"
00045 #include "UnitySettings.h"
00046 #include "config.h"
00047 
00048 #define DASH_WIDGETS_FILE DATADIR"/unity/themes/dash-widgets.json"
00049 
00050 typedef nux::ObjectPtr<nux::BaseTexture> BaseTexturePtr;
00051 
00052 namespace unity
00053 {
00054 namespace dash
00055 {
00056 namespace
00057 {
00058 nux::logging::Logger logger("unity.dash");
00059 
00060 Style* style_instance = nullptr;
00061 const int STATES = 5;
00062 
00063 // These cairo overrides may also be reused somewhere...
00064 void cairo_set_source_rgba(cairo_t* cr, nux::Color const& color)
00065 {
00066   ::cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha);
00067 }
00068 
00069 inline double _align(double val, bool odd=true)
00070 {
00071   double fract = val - (int) val;
00072 
00073   if (odd)
00074   {
00075     // for strokes with an odd line-width
00076     if (fract != 0.5f)
00077       return (double) ((int) val + 0.5f);
00078     else
00079       return val;
00080   }
00081   else
00082   {
00083     // for strokes with an even line-width
00084     if (fract != 0.0f)
00085       return (double) ((int) val);
00086     else
00087       return val;
00088   }
00089 }
00090 
00091 class LazyLoadTexture
00092 {
00093 public:
00094   LazyLoadTexture(std::string const& filename, int size = -1);
00095   nux::BaseTexture* texture();
00096 private:
00097   void LoadTexture();
00098 private:
00099   std::string filename_;
00100   int size_;
00101   BaseTexturePtr texture_;
00102 };
00103 
00104 } // anon namespace
00105 
00106 
00107 class Style::Impl
00108 {
00109 public:
00110   Impl(Style* owner);
00111   ~Impl();
00112 
00113   void Blur(cairo_t* cr, int size);
00114 
00115   void SetDefaultValues();
00116 
00117   void GetTextExtents(int& width,
00118                       int& height,
00119                       int  maxWidth,
00120                       int  maxHeight,
00121                       std::string const& text);
00122 
00123   void Text(cairo_t* cr,
00124             nux::Color const& color,
00125             std::string const& label,
00126             int font_size = -1,
00127             double horizMargin = 4.0,
00128             Alignment alignment = Alignment::CENTER);
00129 
00130   void ButtonOutlinePath(cairo_t* cr, bool align);
00131 
00132   void ButtonOutlinePathSegment(cairo_t* cr, Segment segment);
00133 
00134   void ArrowPath(cairo_t* cr, Arrow arrow);
00135 
00136   cairo_operator_t SetBlendMode(cairo_t* cr, BlendMode mode);
00137 
00138   void DrawOverlay(cairo_t*  cr,
00139                    double    opacity,
00140                    BlendMode mode,
00141                    int       blurSize);
00142 
00143   void RoundedRectSegment(cairo_t*   cr,
00144                           double     aspect,
00145                           double     x,
00146                           double     y,
00147                           double     cornerRadius,
00148                           double     width,
00149                           double     height,
00150                           Segment    segment,
00151                           Arrow      arrow,
00152                           nux::ButtonVisualState state);
00153 
00154   void Refresh();
00155   void OnFontChanged(GtkSettings* object, GParamSpec* pspec);
00156 
00157   // Members
00158   Style* owner_;
00159 
00160   cairo_font_options_t* default_font_options_;
00161 
00162   std::vector<nux::Color> button_label_border_color_;
00163   std::vector<double>     button_label_border_size_;
00164   double                  button_label_text_size_;
00165 
00166   std::vector<nux::Color> button_label_text_color_;
00167   std::vector<nux::Color> button_label_fill_color_;
00168 
00169   std::vector<double>    button_label_overlay_opacity_;
00170   std::vector<BlendMode> button_label_overlay_mode_;
00171   std::vector<int>       button_label_blur_size_;
00172 
00173   nux::Color            regular_text_color_;
00174   double                regular_text_size_;
00175   BlendMode             regular_text_mode_;
00176   FontWeight            regular_text_weight_;
00177 
00178   double                separator_size_;
00179   nux::Color            separator_color_;
00180   double                separator_overlay_opacity_;
00181   BlendMode             separator_overlay_mode_;
00182   int                   separator_blur_size_;
00183 
00184   nux::Color            scrollbar_color_;
00185   double                scrollbar_overlay_opacity_;
00186   BlendMode             scrollbar_overlay_mode_;
00187   int                   scrollbar_blur_size_;
00188   int                   scrollbar_size_;
00189   double                scrollbar_corner_radius_;
00190 
00191   glib::SignalManager signal_manager_;
00192 
00193   nux::Color text_color_;
00194 
00195   int text_width_;
00196   int text_height_;
00197   int number_of_columns_;
00198 
00199   LazyLoadTexture dash_bottom_texture_;
00200   LazyLoadTexture dash_bottom_texture_mask_;
00201   LazyLoadTexture dash_right_texture_;
00202   LazyLoadTexture dash_right_texture_mask_;
00203   LazyLoadTexture dash_corner_texture_;
00204   LazyLoadTexture dash_corner_texture_mask_;
00205   LazyLoadTexture dash_fullscreen_icon_;
00206   LazyLoadTexture dash_left_edge_;
00207   LazyLoadTexture dash_left_corner_;
00208   LazyLoadTexture dash_left_corner_mask_;
00209   LazyLoadTexture dash_left_tile_;
00210   LazyLoadTexture dash_top_corner_;
00211   LazyLoadTexture dash_top_corner_mask_;
00212   LazyLoadTexture dash_top_tile_;
00213 
00214   LazyLoadTexture dash_shine_;
00215 
00216   LazyLoadTexture search_magnify_texture_;
00217   LazyLoadTexture search_circle_texture_;
00218   LazyLoadTexture search_close_texture_;
00219   LazyLoadTexture search_spin_texture_;
00220 
00221   LazyLoadTexture group_unexpand_texture_;
00222   LazyLoadTexture group_expand_texture_;
00223 
00224   LazyLoadTexture star_deselected_texture_;
00225   LazyLoadTexture star_selected_texture_;
00226   LazyLoadTexture star_highlight_texture_;
00227 };
00228 
00229 Style::Impl::Impl(Style* owner)
00230   : owner_(owner)
00231   , button_label_border_color_(STATES)
00232   , button_label_border_size_(STATES)
00233   , button_label_text_color_(STATES)
00234   , button_label_fill_color_(STATES)
00235   , button_label_overlay_opacity_(STATES)
00236   , button_label_overlay_mode_(STATES)
00237   , button_label_blur_size_(STATES)
00238   , text_color_(nux::color::White)
00239   , text_width_(0)
00240   , text_height_(0)
00241   , number_of_columns_(6)
00242   , dash_bottom_texture_("/dash_bottom_border_tile.png")
00243   , dash_bottom_texture_mask_("/dash_bottom_border_tile_mask.png")
00244   , dash_right_texture_("/dash_right_border_tile.png")
00245   , dash_right_texture_mask_("/dash_right_border_tile_mask.png")
00246   , dash_corner_texture_("/dash_bottom_right_corner.png")
00247   , dash_corner_texture_mask_("/dash_bottom_right_corner_mask.png")
00248   , dash_fullscreen_icon_("/dash_fullscreen_icon.png")
00249   , dash_left_edge_("/dash_left_edge.png")
00250   , dash_left_corner_("/dash_bottom_left_corner.png")
00251   , dash_left_corner_mask_("/dash_bottom_left_corner_mask.png")
00252   , dash_left_tile_("/dash_left_tile.png")
00253   , dash_top_corner_("/dash_top_right_corner.png")
00254   , dash_top_corner_mask_("/dash_top_right_corner_mask.png")
00255   , dash_top_tile_("/dash_top_tile.png")
00256   , dash_shine_("/dash_sheen.png")
00257   , search_magnify_texture_("/search_magnify.png")
00258   , search_circle_texture_("/search_circle.svg", 32)
00259   , search_close_texture_("/search_close.svg", 32)
00260   , search_spin_texture_("/search_spin.svg", 32)
00261   , group_unexpand_texture_("/dash_group_unexpand.png")
00262   , group_expand_texture_("/dash_group_expand.png")
00263   , star_deselected_texture_("/star_deselected.png")
00264   , star_selected_texture_("/star_selected.png")
00265   , star_highlight_texture_("/star_highlight.png")
00266 {
00267   signal_manager_.Add(new glib::Signal<void, GtkSettings*, GParamSpec*>
00268                       (gtk_settings_get_default(),
00269                        "notify::gtk-font-name",
00270                        sigc::mem_fun(this, &Impl::OnFontChanged)));
00271   signal_manager_.Add(new glib::Signal<void, GtkSettings*, GParamSpec*>
00272                       (gtk_settings_get_default(),
00273                        "notify::gtk-xft-dpi",
00274                        sigc::mem_fun(this, &Impl::OnFontChanged)));
00275   Refresh();
00276 
00277   // create fallback font-options
00278   default_font_options_ = cairo_font_options_create();
00279   if (cairo_font_options_status(default_font_options_) == CAIRO_STATUS_SUCCESS)
00280   {
00281     cairo_font_options_set_antialias(default_font_options_,
00282                                      CAIRO_ANTIALIAS_GRAY);
00283     cairo_font_options_set_subpixel_order(default_font_options_,
00284                                           CAIRO_SUBPIXEL_ORDER_RGB);
00285     cairo_font_options_set_hint_style(default_font_options_,
00286                                       CAIRO_HINT_STYLE_SLIGHT);
00287     cairo_font_options_set_hint_metrics(default_font_options_,
00288                                         CAIRO_HINT_METRICS_ON);
00289   }
00290 
00291   json::Parser parser;
00292   // Since the parser skips values if they are not found, make sure everything
00293   // is initialised.
00294   SetDefaultValues();
00295   if (!parser.Open(DASH_WIDGETS_FILE))
00296     return;
00297 
00298   // button-label
00299   parser.ReadColors("button-label", "border-color", "border-opacity",
00300                     button_label_border_color_);
00301   parser.ReadDoubles("button-label", "border-size", button_label_border_size_);
00302   parser.ReadDouble("button-label", "text-size", button_label_text_size_);
00303   parser.ReadColors("button-label", "text-color", "text-opacity",
00304                     button_label_text_color_);
00305   parser.ReadColors("button-label", "fill-color", "fill-opacity",
00306                     button_label_fill_color_);
00307   parser.ReadDoubles("button-label", "overlay-opacity", button_label_overlay_opacity_);
00308 
00309   std::map<std::string, BlendMode> blend_mode_map;
00310   blend_mode_map["normal"] = BlendMode::NORMAL;
00311   blend_mode_map["multiply"] = BlendMode::MULTIPLY;
00312   blend_mode_map["screen"] = BlendMode::SCREEN;
00313 
00314   parser.ReadMappedStrings("button-label", "overlay-mode", blend_mode_map,
00315                            button_label_overlay_mode_);
00316   parser.ReadInts("button-label", "blur-size", button_label_blur_size_);
00317 
00318   // regular-text
00319   parser.ReadColor("regular-text", "text-color", "text-opacity",
00320                    regular_text_color_);
00321   parser.ReadDouble("regular-text", "text-size", regular_text_size_);
00322   parser.ReadMappedString("regular-text", "text-mode", blend_mode_map,
00323                           regular_text_mode_);
00324 
00325   std::map<std::string, FontWeight> font_weight_map;
00326   font_weight_map["light"] = FontWeight::LIGHT;
00327   font_weight_map["regular"] = FontWeight::REGULAR;
00328   font_weight_map["bold"] = FontWeight::BOLD;
00329 
00330   parser.ReadMappedString("regular-text", "text-weight", font_weight_map,
00331                           regular_text_weight_);
00332 
00333   // separator
00334   parser.ReadDouble("separator", "size", separator_size_);
00335   parser.ReadColor("separator", "color", "opacity", separator_color_);
00336   parser.ReadDouble("separator", "overlay-opacity", separator_overlay_opacity_);
00337   parser.ReadMappedString("separator", "overlay-mode", blend_mode_map,
00338                           separator_overlay_mode_);
00339   parser.ReadInt("separator", "blur-size", separator_blur_size_);
00340 
00341   // scrollbar
00342   parser.ReadColor("scrollbar", "color", "opacity", scrollbar_color_);
00343   parser.ReadDouble("scrollbar", "overlay-opacity", scrollbar_overlay_opacity_);
00344   parser.ReadMappedString("scrollbar", "overlay-mode", blend_mode_map,
00345                           scrollbar_overlay_mode_);
00346   parser.ReadInt("scrollbar", "blur-size", scrollbar_blur_size_);
00347   parser.ReadInt("scrollbar", "size", scrollbar_size_);
00348   parser.ReadDouble("scrollbar", "corner-radius", scrollbar_corner_radius_);
00349 }
00350 
00351 Style::Impl::~Impl()
00352 {
00353   if (cairo_font_options_status(default_font_options_) == CAIRO_STATUS_SUCCESS)
00354     cairo_font_options_destroy(default_font_options_);
00355 }
00356 
00357 void Style::Impl::Refresh()
00358 {
00359   const char* const SAMPLE_MAX_TEXT = "Chromium Web Browser";
00360   GtkSettings* settings = ::gtk_settings_get_default();
00361 
00362   nux::CairoGraphics util_cg(CAIRO_FORMAT_ARGB32, 1, 1);
00363   cairo_t* cr = util_cg.GetInternalContext();
00364 
00365   glib::String font_description;
00366   int dpi = 0;
00367   ::g_object_get(settings,
00368                  "gtk-font-name", &font_description,
00369                  "gtk-xft-dpi", &dpi,
00370                  NULL);
00371   PangoFontDescription* desc = ::pango_font_description_from_string(font_description);
00372   ::pango_font_description_set_weight(desc, PANGO_WEIGHT_NORMAL);
00373   ::pango_font_description_set_size(desc, 9 * PANGO_SCALE);
00374 
00375   glib::Object<PangoLayout> layout(::pango_cairo_create_layout(cr));
00376   ::pango_layout_set_font_description(layout, desc);
00377   ::pango_layout_set_text(layout, SAMPLE_MAX_TEXT, -1);
00378 
00379   PangoContext* cxt = ::pango_layout_get_context(layout);
00380 
00381   GdkScreen* screen = ::gdk_screen_get_default();
00382   ::pango_cairo_context_set_font_options(cxt, ::gdk_screen_get_font_options(screen));
00383   float pango_scale = PANGO_SCALE;
00384   ::pango_cairo_context_set_resolution(cxt, dpi / pango_scale);
00385   ::pango_layout_context_changed(layout);
00386 
00387   PangoRectangle log_rect;
00388   ::pango_layout_get_extents(layout, NULL, &log_rect);
00389   text_width_ = log_rect.width / PANGO_SCALE;
00390   text_height_ = log_rect.height / PANGO_SCALE;
00391 
00392   owner_->changed.emit();
00393 
00394   pango_font_description_free(desc);
00395 }
00396 
00397 
00398 void Style::Impl::OnFontChanged(GtkSettings* object, GParamSpec* pspec)
00399 {
00400   Refresh();
00401 }
00402 
00403 
00404 Style::Style()
00405   : always_maximised(false)
00406   , pimpl(new Impl(this))
00407 {
00408   if (style_instance)
00409   {
00410     LOG_ERROR(logger) << "More than one dash::Style created.";
00411   }
00412   else
00413   {
00414     style_instance = this;
00415   }
00416 
00417   auto formfactor_lambda = [this] () 
00418   {
00419     FormFactor formfactor = Settings::Instance().GetFormFactor();
00420     always_maximised = (formfactor == FormFactor::NETBOOK || formfactor == FormFactor::TV); 
00421   };
00422 
00423   Settings::Instance().changed.connect(formfactor_lambda);
00424   formfactor_lambda();
00425 }
00426 
00427 Style::~Style ()
00428 {
00429   delete pimpl;
00430   if (style_instance == this)
00431     style_instance = nullptr;
00432 }
00433 
00434 Style& Style::Instance()
00435 {
00436   if (!style_instance)
00437   {
00438     LOG_ERROR(logger) << "No dash::Style created yet.";
00439   }
00440 
00441   return *style_instance;
00442 }
00443 
00444 void Style::RoundedRect(cairo_t* cr,
00445                             double   aspect,
00446                             double   x,
00447                             double   y,
00448                             double   cornerRadius,
00449                             double   width,
00450                             double   height)
00451 {
00452   // sanity check
00453   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS &&
00454       cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
00455     return;
00456 
00457   bool odd = true;
00458 
00459   odd = cairo_get_line_width (cr) == 2.0 ? false : true;
00460 
00461   double radius = cornerRadius / aspect;
00462 
00463   // top-left, right of the corner
00464   cairo_move_to(cr, _align (x + radius, odd), _align (y, odd));
00465 
00466   // top-right, left of the corner
00467   cairo_line_to(cr, _align(x + width - radius, odd), _align(y, odd));
00468 
00469   // top-right, below the corner
00470   cairo_arc(cr,
00471             _align(x + width - radius, odd),
00472             _align(y + radius, odd),
00473             radius,
00474             -90.0f * G_PI / 180.0f,
00475             0.0f * G_PI / 180.0f);
00476 
00477   // bottom-right, above the corner
00478   cairo_line_to(cr, _align(x + width, odd), _align(y + height - radius, odd));
00479 
00480   // bottom-right, left of the corner
00481   cairo_arc(cr,
00482             _align(x + width - radius, odd),
00483             _align(y + height - radius, odd),
00484             radius,
00485             0.0f * G_PI / 180.0f,
00486             90.0f * G_PI / 180.0f);
00487 
00488   // bottom-left, right of the corner
00489   cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd));
00490 
00491   // bottom-left, above the corner
00492   cairo_arc(cr,
00493             _align(x + radius, odd),
00494             _align(y + height - radius, odd),
00495             radius,
00496             90.0f * G_PI / 180.0f,
00497             180.0f * G_PI / 180.0f);
00498 
00499   // top-left, right of the corner
00500   cairo_arc(cr,
00501             _align(x + radius, odd),
00502             _align(y + radius, odd),
00503             radius,
00504             180.0f * G_PI / 180.0f,
00505             270.0f * G_PI / 180.0f);
00506 }
00507 
00508 static inline void _blurinner(guchar* pixel,
00509                               gint*   zR,
00510                               gint*   zG,
00511                               gint*   zB,
00512                               gint*   zA,
00513                               gint    alpha,
00514                               gint    aprec,
00515                               gint    zprec)
00516 {
00517   gint   r;
00518   gint   g;
00519   gint   b;
00520   guchar a;
00521 
00522   r = *pixel;
00523   g = *(pixel + 1);
00524   b = *(pixel + 2);
00525   a = *(pixel + 3);
00526 
00527   *zR += (alpha * ((r << zprec) - *zR)) >> aprec;
00528   *zG += (alpha * ((g << zprec) - *zG)) >> aprec;
00529   *zB += (alpha * ((b << zprec) - *zB)) >> aprec;
00530   *zA += (alpha * ((a << zprec) - *zA)) >> aprec;
00531 
00532   *pixel       = *zR >> zprec;
00533   *(pixel + 1) = *zG >> zprec;
00534   *(pixel + 2) = *zB >> zprec;
00535   *(pixel + 3) = *zA >> zprec;
00536 }
00537 
00538 static inline void _blurrow(guchar* pixels,
00539                             gint    width,
00540                             gint    height,
00541                             gint    channels,
00542                             gint    line,
00543                             gint    alpha,
00544                             gint    aprec,
00545                             gint    zprec)
00546 {
00547   gint    zR;
00548   gint    zG;
00549   gint    zB;
00550   gint    zA;
00551   gint    index;
00552   guchar* scanline;
00553 
00554   scanline = &(pixels[line * width * channels]);
00555 
00556   zR = *scanline << zprec;
00557   zG = *(scanline + 1) << zprec;
00558   zB = *(scanline + 2) << zprec;
00559   zA = *(scanline + 3) << zprec;
00560 
00561   for (index = 0; index < width; index ++)
00562     _blurinner(&scanline[index * channels], &zR, &zG, &zB, &zA, alpha, aprec,
00563                zprec);
00564 
00565   for (index = width - 2; index >= 0; index--)
00566     _blurinner(&scanline[index * channels], &zR, &zG, &zB, &zA, alpha, aprec,
00567                zprec);
00568 }
00569 
00570 static inline void _blurcol(guchar* pixels,
00571                             gint    width,
00572                             gint    height,
00573                             gint    channels,
00574                             gint    x,
00575                             gint    alpha,
00576                             gint    aprec,
00577                             gint    zprec)
00578 {
00579   gint zR;
00580   gint zG;
00581   gint zB;
00582   gint zA;
00583   gint index;
00584   guchar* ptr;
00585 
00586   ptr = pixels;
00587 
00588   ptr += x * channels;
00589 
00590   zR = *((guchar*) ptr    ) << zprec;
00591   zG = *((guchar*) ptr + 1) << zprec;
00592   zB = *((guchar*) ptr + 2) << zprec;
00593   zA = *((guchar*) ptr + 3) << zprec;
00594 
00595   for (index = width; index < (height - 1) * width; index += width)
00596     _blurinner((guchar*) &ptr[index * channels], &zR, &zG, &zB, &zA, alpha,
00597                aprec, zprec);
00598 
00599   for (index = (height - 2) * width; index >= 0; index -= width)
00600     _blurinner((guchar*) &ptr[index * channels], &zR, &zG, &zB, &zA, alpha,
00601                aprec, zprec);
00602 }
00603 
00604 //
00605 // pixels   image-data
00606 // width    image-width
00607 // height   image-height
00608 // channels image-channels
00609 //
00610 // in-place blur of image 'img' with kernel of approximate radius 'radius'
00611 //
00612 // blurs with two sided exponential impulse response
00613 //
00614 // aprec = precision of alpha parameter in fixed-point format 0.aprec
00615 //
00616 // zprec = precision of state parameters zR,zG,zB and zA in fp format 8.zprec
00617 //
00618 void _expblur(guchar* pixels,
00619               gint    width,
00620               gint    height,
00621               gint    channels,
00622               gint    radius,
00623               gint    aprec,
00624               gint    zprec)
00625 {
00626   gint alpha;
00627   gint row = 0;
00628   gint col = 0;
00629 
00630   if (radius < 1)
00631     return;
00632 
00633   // calculate the alpha such that 90% of
00634   // the kernel is within the radius.
00635   // (Kernel extends to infinity)
00636   alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
00637 
00638   for (; row < height; row++)
00639     _blurrow(pixels, width, height, channels, row, alpha, aprec, zprec);
00640 
00641   for(; col < width; col++)
00642     _blurcol(pixels, width, height, channels, col, alpha, aprec, zprec);
00643 
00644   return;
00645 }
00646 
00647 void Style::Blur(cairo_t* cr, int size)
00648 {
00649   pimpl->Blur(cr, size);
00650 }
00651 
00652 void Style::Impl::Blur(cairo_t* cr, int size)
00653 {
00654   // sanity check
00655   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS &&
00656       cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
00657     return;
00658 
00659   cairo_surface_t* surface;
00660   guchar*          pixels;
00661   guint            width;
00662   guint            height;
00663   cairo_format_t   format;
00664 
00665   surface = cairo_get_target(cr);
00666 
00667   // before we mess with the surface execute any pending drawing
00668   cairo_surface_flush(surface);
00669 
00670   pixels = cairo_image_surface_get_data(surface);
00671   width  = cairo_image_surface_get_width(surface);
00672   height = cairo_image_surface_get_height(surface);
00673   format = cairo_image_surface_get_format(surface);
00674 
00675   switch (format)
00676   {
00677   case CAIRO_FORMAT_ARGB32:
00678     _expblur(pixels, width, height, 4, size, 16, 7);
00679     break;
00680 
00681   case CAIRO_FORMAT_RGB24:
00682     _expblur(pixels, width, height, 3, size, 16, 7);
00683     break;
00684 
00685   case CAIRO_FORMAT_A8:
00686     _expblur(pixels, width, height, 1, size, 16, 7);
00687     break;
00688 
00689   default :
00690     // do nothing
00691     break;
00692   }
00693 
00694   // inform cairo we altered the surfaces contents
00695   cairo_surface_mark_dirty(surface);
00696 }
00697 
00698 void Style::Impl::SetDefaultValues()
00699 {
00700   // button-label
00701   button_label_border_color_[nux::VISUAL_STATE_NORMAL] = nux::Color(0.53, 1.0, 0.66, 0.5);
00702   button_label_border_color_[nux::VISUAL_STATE_PRESSED] = nux::Color(1.0, 1.0, 1.0, 0.8);
00703   button_label_border_color_[nux::VISUAL_STATE_PRELIGHT] = nux::Color(0.06, 0.13, 1.0, 0.5);
00704   //button_label_border_color_[nux::NUX_STATE_SELECTED] = nux::Color(0.07, 0.2, 0.33, 0.5);
00705   //button_label_border_color_[nux::NUX_STATE_INSENSITIVE] = nux::Color(0.39, 0.26, 0.12, 0.5);
00706 
00707   button_label_border_size_[nux::VISUAL_STATE_NORMAL]          = 0.5;
00708   button_label_border_size_[nux::VISUAL_STATE_PRESSED]          = 2.0;
00709   button_label_border_size_[nux::VISUAL_STATE_PRELIGHT]        = 0.5;
00710   //button_label_border_size_[nux::NUX_STATE_SELECTED]        = 0.5;
00711   //button_label_border_size_[nux::NUX_STATE_INSENSITIVE]     = 0.5;
00712 
00713   button_label_text_size_                                   = 1.0;
00714 
00715   button_label_text_color_[nux::VISUAL_STATE_NORMAL] = nux::color::White;
00716   button_label_text_color_[nux::VISUAL_STATE_PRESSED] = nux::color::Black;
00717   button_label_text_color_[nux::VISUAL_STATE_PRELIGHT] = nux::color::White;
00718   //button_label_text_color_[nux::NUX_STATE_SELECTED] = nux::color::White;
00719   //button_label_text_color_[nux::NUX_STATE_INSENSITIVE] = nux::color::White;
00720 
00721   button_label_fill_color_[nux::VISUAL_STATE_NORMAL] = nux::color::Transparent;
00722   button_label_fill_color_[nux::VISUAL_STATE_PRESSED] = nux::color::Transparent;
00723   button_label_fill_color_[nux::VISUAL_STATE_PRELIGHT] = nux::color::Transparent;
00724   //button_label_fill_color_[nux::NUX_STATE_SELECTED] = nux::color::Transparent;
00725   //button_label_fill_color_[nux::NUX_STATE_INSENSITIVE] = nux::color::Transparent;
00726 
00727   button_label_overlay_opacity_[nux::VISUAL_STATE_NORMAL]      = 0.0;
00728   button_label_overlay_opacity_[nux::VISUAL_STATE_PRESSED]      = 0.3;
00729   button_label_overlay_opacity_[nux::VISUAL_STATE_PRELIGHT]    = 0.0;
00730   //button_label_overlay_opacity_[nux::NUX_STATE_SELECTED]    = 0.0;
00731   //button_label_overlay_opacity_[nux::NUX_STATE_INSENSITIVE] = 0.0;
00732 
00733   button_label_overlay_mode_[nux::VISUAL_STATE_NORMAL]         = BlendMode::NORMAL;
00734   button_label_overlay_mode_[nux::VISUAL_STATE_PRESSED]         = BlendMode::NORMAL;
00735   button_label_overlay_mode_[nux::VISUAL_STATE_PRELIGHT]       = BlendMode::NORMAL;
00736   //button_label_overlay_mode_[nux::NUX_STATE_SELECTED]       = BlendMode::NORMAL;
00737   //button_label_overlay_mode_[nux::NUX_STATE_INSENSITIVE]    = BlendMode::NORMAL;
00738 
00739   button_label_blur_size_[nux::VISUAL_STATE_NORMAL]            = 0;
00740   button_label_blur_size_[nux::VISUAL_STATE_PRESSED]            = 5;
00741   button_label_blur_size_[nux::VISUAL_STATE_PRELIGHT]          = 0;
00742   //button_label_blur_size_[nux::NUX_STATE_SELECTED]          = 0;
00743   //button_label_blur_size_[nux::NUX_STATE_INSENSITIVE]       = 0;
00744 
00745   // regular-text
00746   regular_text_color_ = nux::color::White;
00747   regular_text_size_       = 13.0;
00748   regular_text_mode_       = BlendMode::NORMAL;
00749   regular_text_weight_     = FontWeight::LIGHT;
00750 
00751   // separator
00752   separator_size_           = 1.0;
00753   separator_color_ = nux::Color(1.0, 1.0, 1.0, 0.15);
00754   separator_overlay_opacity_ = 0.47;
00755   separator_overlay_mode_    = BlendMode::NORMAL;
00756   separator_blur_size_       = 6;
00757 
00758   // scrollbar
00759   scrollbar_color_ = nux::color::White;
00760   scrollbar_overlay_opacity_ = 0.3;
00761   scrollbar_overlay_mode_    = BlendMode::NORMAL;
00762   scrollbar_blur_size_       = 5;
00763   scrollbar_size_           = 3;
00764   scrollbar_corner_radius_   = 1.5;
00765 }
00766 
00767 void Style::Impl::ArrowPath(cairo_t* cr, Arrow arrow)
00768 {
00769   double x  = 0.0;
00770   double y  = 0.0;
00771   double w  = cairo_image_surface_get_width(cairo_get_target(cr));
00772   double h  = cairo_image_surface_get_height(cairo_get_target(cr));
00773   /*double xt = 0.0;
00774     double yt = 0.0;*/
00775 
00776   // the real shape from the SVG
00777   // 3.5/1.5, 20.5/22.5, (17x21)
00778   /*xt = 16.25;
00779     yt = 9.028;
00780     cairo_move_to (cr, xt, yt);
00781     cairo_curve_to (cr, xt - 1.511, yt - 1.006, xt - 3.019, yt - 1.971, xt - 4.527, yt - 2.897);
00782     xt -= 4.527;
00783     yt -= 2.897
00784     cairo_curve_to (cr, 10.213, 5.2, 8.743, 4.335, 7.313, 3.532);
00785     cairo_curve_to (cr, 8.743, 4.335, 4.613, 2.051, 3.5, 1.5);
00786     cairo_rel_line_to (cr, 0.0, 21.0);
00787     cairo_rel_curve_to (cr, 1.164, -0.552, 2.461, -1.229, 3.892, -2.032);
00788     cairo_rel_curve_to (cr, 1.431, -0.803, 2.9, -1.682, 4.409, -2.634);
00789     cairo_rel_curve_to (cr, 1.51, -0.953, 3.004, -1.932, 4.488, -2.937);
00790     cairo_rel_curve_to (cr, 1.481, -1.002, 2.887, -1.981, 4.211, -2.935);
00791     cairo_curve_to (cr, 19.176, 11.009, 17.759, 10.03, 16.25, 9.028);
00792     cairo_close_path (cr);*/
00793 
00794   if (arrow == Arrow::LEFT || arrow == Arrow::BOTH)
00795   {
00796     x = 1.0;
00797     y = h / 2.0 - 3.5;
00798     cairo_move_to(cr, _align(x), _align(y));
00799     cairo_line_to(cr, _align(x + 5.0), _align(y + 3.5));
00800     cairo_line_to(cr, _align(x), _align(y + 7.0));
00801     cairo_close_path(cr);
00802   }
00803 
00804   if (arrow == Arrow::RIGHT || arrow == Arrow::BOTH)
00805   {
00806     x = w - 1.0;
00807     y = h / 2.0 - 3.5;
00808     cairo_move_to(cr, _align(x), _align(y));
00809     cairo_line_to(cr, _align(x - 5.0), _align(y + 3.5));
00810     cairo_line_to(cr, _align(x), _align(y + 7.0));
00811     cairo_close_path(cr);
00812   }
00813 }
00814 
00815 void Style::Impl::ButtonOutlinePath (cairo_t* cr, bool align)
00816 {
00817   double x  = 2.0;
00818   double y  = 2.0;
00819   double w  = cairo_image_surface_get_width(cairo_get_target(cr)) - 4.0;
00820   double h  = cairo_image_surface_get_height(cairo_get_target(cr)) - 4.0;
00821   double xt = 0.0;
00822   double yt = 0.0;
00823 
00824   // - these absolute values are the "cost" of getting only a SVG from design
00825   // and not a generic formular how to approximate the curve-shape, thus
00826   // the smallest possible button-size is 22.18x24.0
00827   double width  = w - 22.18;
00828   double height = h - 24.0;
00829 
00830   xt = x + width + 22.18;
00831   yt = y + 12.0;
00832 
00833   if (align)
00834   {
00835     // top right
00836     cairo_move_to(cr, _align(xt), _align(yt));
00837     cairo_curve_to(cr, _align(xt - 0.103),
00838                    _align(yt - 4.355),
00839                    _align(xt - 1.037),
00840                    _align(yt - 7.444),
00841                    _align(xt - 2.811),
00842                    _align(yt - 9.267));
00843     xt -= 2.811;
00844     yt -= 9.267;
00845     cairo_curve_to(cr, _align(xt - 1.722),
00846                    _align(yt - 1.823),
00847                    _align(xt - 4.531),
00848                    _align(yt - 2.735),
00849                    _align(xt - 8.28),
00850                    _align(yt - 2.735));
00851     xt -= 8.28;
00852     yt -= 2.735;
00853 
00854     // top
00855     cairo_line_to(cr, _align(xt - width), _align(yt));
00856     xt -= width;
00857 
00858     // top left
00859     cairo_curve_to(cr, _align(xt - 3.748),
00860                    _align(yt),
00861                    _align(xt - 6.507),
00862                    _align(yt + 0.912),
00863                    _align(xt - 8.279),
00864                    _align(yt + 2.735));
00865     xt -= 8.279;
00866     yt += 2.735;
00867     cairo_curve_to(cr, _align(xt - 1.773),
00868                    _align(yt + 1.822),
00869                    _align(xt - 2.708),
00870                    _align(yt + 4.911),
00871                    _align(xt - 2.811),
00872                    _align(yt + 9.267));
00873     xt -= 2.811;
00874     yt += 9.267;
00875 
00876     // left
00877     cairo_line_to(cr, _align(xt), _align(yt + height));
00878     yt += height;
00879 
00880     // bottom left
00881     cairo_curve_to(cr, _align(xt + 0.103),
00882                    _align(yt + 4.355),
00883                    _align(xt + 1.037),
00884                    _align(yt + 7.444),
00885                    _align(xt + 2.811),
00886                    _align(yt + 9.267));
00887     xt += 2.811;
00888     yt += 9.267;
00889     cairo_curve_to(cr, _align(xt + 1.772),
00890                    _align(yt + 1.823),
00891                    _align(xt + 4.531),
00892                    _align(yt + 2.735),
00893                    _align(xt + 8.28),
00894                    _align(yt + 2.735));
00895     xt += 8.28;
00896     yt += 2.735;
00897 
00898     // bottom
00899     cairo_line_to(cr, _align(xt + width), _align(yt));
00900     xt += width;
00901 
00902     // bottom right
00903     cairo_curve_to(cr, _align(xt + 3.748),
00904                    _align(yt),
00905                    _align(xt + 6.507),
00906                    _align(yt - 0.912),
00907                    _align(xt + 8.279),
00908                    _align(yt - 2.735));
00909     xt += 8.279;
00910     yt -= 2.735;
00911     cairo_curve_to(cr, _align(xt + 1.773),
00912                    _align(yt - 1.822),
00913                    _align(xt + 2.708),
00914                    _align(yt - 4.911),
00915                    _align(xt + 2.811),
00916                    _align(yt - 9.267));
00917   }
00918   else
00919   {
00920     // top right
00921     cairo_move_to(cr, x + width + 22.18, y + 12.0);
00922     cairo_rel_curve_to(cr, -0.103, -4.355, -1.037, -7.444, -2.811, -9.267);
00923     cairo_rel_curve_to(cr, -1.722, -1.823, -4.531, -2.735, -8.28, -2.735);
00924 
00925     // top
00926     cairo_rel_line_to(cr, -width, 0.0);
00927 
00928     // top left
00929     cairo_rel_curve_to(cr, -3.748, 0.0, -6.507, 0.912, -8.279, 2.735);
00930     cairo_rel_curve_to(cr, -1.773, 1.822, -2.708, 4.911, -2.811, 9.267);
00931 
00932     // left
00933     cairo_rel_line_to(cr, 0.0, height);
00934 
00935     // bottom left
00936     cairo_rel_curve_to(cr, 0.103, 4.355, 1.037, 7.444, 2.811, 9.267);
00937     cairo_rel_curve_to(cr, 1.772, 1.823, 4.531, 2.735, 8.28, 2.735);
00938 
00939     // bottom
00940     cairo_rel_line_to(cr, width, 0.0);
00941 
00942     // bottom right
00943     cairo_rel_curve_to(cr, 3.748, 0.0, 6.507, -0.912, 8.279, -2.735);
00944     cairo_rel_curve_to(cr, 1.773, -1.822, 2.708, -4.911, 2.811, -9.267);
00945   }
00946 
00947   // right
00948   cairo_close_path(cr);
00949 }
00950 
00951 void Style::Impl::RoundedRectSegment(cairo_t*   cr,
00952                                          double     aspect,
00953                                          double     x,
00954                                          double     y,
00955                                          double     cornerRadius,
00956                                          double     width,
00957                                          double     height,
00958                                          Segment    segment,
00959                                          Arrow      arrow,
00960                                          nux::ButtonVisualState state)
00961 {
00962   double radius  = cornerRadius / aspect;
00963   double arrow_w = radius / 1.5;
00964   double arrow_h = radius / 2.0;
00965   bool odd = true;
00966 
00967   odd = cairo_get_line_width (cr) == 2.0 ? false : true;
00968 
00969   switch (segment)
00970   {
00971   case Segment::LEFT:
00972     // top-left, right of the corner
00973     cairo_move_to(cr, _align(x + radius, odd), _align(y, odd));
00974 
00975     // top-right
00976     cairo_line_to(cr, _align(x + width, odd), _align(y, odd));
00977 
00978     if (arrow == Arrow::RIGHT && state == nux::VISUAL_STATE_PRESSED)
00979               {
00980       cairo_line_to(cr, _align(x + width, odd),           _align(y + height / 2.0 - arrow_h, odd));
00981       cairo_line_to(cr, _align(x + width - arrow_w, odd), _align(y + height / 2.0, odd));
00982       cairo_line_to(cr, _align(x + width, odd),           _align(y + height / 2.0 + arrow_h, odd));
00983               }
00984 
00985     // bottom-right
00986     cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
00987 
00988     // bottom-left, right of the corner
00989     cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd));
00990 
00991     // bottom-left, above the corner
00992     cairo_arc(cr,
00993               _align(x, odd) + _align(radius, odd),
00994               _align(y + height, odd) - _align(radius, odd),
00995               _align(radius, odd),
00996               90.0f * G_PI / 180.0f,
00997               180.0f * G_PI / 180.0f);
00998 
00999     // left, right of the corner
01000     cairo_line_to(cr, _align(x, odd), _align(y + radius, odd));
01001 
01002     // top-left, right of the corner
01003     cairo_arc(cr,
01004               _align(x, odd) + _align(radius, odd),
01005               _align(y, odd) + _align(radius, odd),
01006               _align(radius, odd),
01007               180.0f * G_PI / 180.0f,
01008               270.0f * G_PI / 180.0f);
01009 
01010     break;
01011 
01012   case Segment::MIDDLE:
01013     // top-left
01014     cairo_move_to(cr, _align(x, odd), _align(y, odd));
01015 
01016     // top-right
01017     cairo_line_to(cr, _align(x + width, odd), _align(y, odd));
01018 
01019     if ((arrow == Arrow::RIGHT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED)
01020               {
01021       cairo_line_to(cr, _align(x + width, odd),           _align(y + height / 2.0 - arrow_h, odd));
01022       cairo_line_to(cr, _align(x + width - arrow_w, odd), _align(y + height / 2.0, odd));
01023       cairo_line_to(cr, _align(x + width, odd),           _align(y + height / 2.0 + arrow_h, odd));
01024               }
01025 
01026     // bottom-right
01027     cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
01028 
01029     // bottom-left
01030     cairo_line_to(cr, _align(x, odd), _align(y + height, odd));
01031 
01032     if ((arrow == Arrow::LEFT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED)
01033               {
01034       cairo_line_to(cr, _align(x, odd),           _align(y + height / 2.0 + arrow_h, odd));
01035       cairo_line_to(cr, _align(x + arrow_w, odd), _align(y + height / 2.0, odd));
01036       cairo_line_to(cr, _align(x, odd),           _align(y + height / 2.0 - arrow_h, odd));
01037               }
01038 
01039     // back to top-left
01040     cairo_close_path(cr);
01041     break;
01042 
01043   case Segment::RIGHT:
01044     // top-left, right of the corner
01045     cairo_move_to(cr, _align(x, odd), _align(y, odd));
01046 
01047     // top-right, left of the corner
01048     cairo_line_to(cr, _align(x + width - radius, odd), _align(y, odd));
01049 
01050     // top-right, below the corner
01051     cairo_arc(cr,
01052               _align(x + width, odd) - _align(radius, odd),
01053               _align(y, odd) + _align(radius, odd),
01054               _align(radius, odd),
01055               -90.0f * G_PI / 180.0f,
01056               0.0f * G_PI / 180.0f);
01057 
01058     // bottom-right, above the corner
01059     cairo_line_to(cr, _align(x + width, odd), _align(y + height - radius, odd));
01060 
01061     // bottom-right, left of the corner
01062     cairo_arc(cr,
01063               _align(x + width, odd) - _align(radius, odd),
01064               _align(y + height, odd) - _align(radius, odd),
01065               _align(radius, odd),
01066               0.0f * G_PI / 180.0f,
01067               90.0f * G_PI / 180.0f);
01068 
01069     // bottom-left
01070     cairo_line_to(cr, _align(x, odd), _align(y + height, odd));
01071 
01072     if (arrow == Arrow::LEFT && state == nux::VISUAL_STATE_PRESSED)
01073               {
01074       cairo_line_to(cr, _align(x, odd),           _align(y + height / 2.0 + arrow_h, odd));
01075       cairo_line_to(cr, _align(x + arrow_w, odd), _align(y + height / 2.0, odd));
01076       cairo_line_to(cr, _align(x, odd),           _align(y + height / 2.0 - arrow_h, odd));
01077               }
01078 
01079     // back to top-left
01080     cairo_close_path(cr);
01081     break;
01082   }
01083 }
01084 
01085 void Style::Impl::ButtonOutlinePathSegment(cairo_t* cr, Segment segment)
01086 {
01087   double   x  = 0.0;
01088   double   y  = 2.0;
01089   double   w  = cairo_image_surface_get_width(cairo_get_target(cr));
01090   double   h  = cairo_image_surface_get_height(cairo_get_target(cr)) - 4.0;
01091   double   xt = 0.0;
01092   double   yt = 0.0;
01093 
01094   // - these absolute values are the "cost" of getting only a SVG from design
01095   // and not a generic formular how to approximate the curve-shape, thus
01096   // the smallest possible button-size is 22.18x24.0
01097   double width  = w - 22.18;
01098   double height = h - 24.0;
01099 
01100   xt = x + width + 22.18;
01101   yt = y + 12.0;
01102 
01103   switch (segment)
01104   {
01105   case Segment::LEFT:
01106     yt -= (9.267 + 2.735);
01107     cairo_move_to(cr, _align(xt), _align(yt));
01108     xt -= (2.811 + 8.28);
01109 
01110     // top
01111     cairo_line_to(cr, _align(xt - width), _align(yt));
01112     xt -= width;
01113 
01114     // top left
01115     cairo_curve_to(cr, _align(xt - 3.748),
01116                    _align(yt),
01117                    _align(xt - 6.507),
01118                    _align(yt + 0.912),
01119                    _align(xt - 8.279),
01120                    _align(yt + 2.735));
01121     xt -= 8.279;
01122     yt += 2.735;
01123     cairo_curve_to(cr, _align(xt - 1.773),
01124                    _align(yt + 1.822),
01125                    _align(xt - 2.708),
01126                    _align(yt + 4.911),
01127                    _align(xt - 2.811),
01128                    _align(yt + 9.267));
01129     xt -= 2.811;
01130     yt += 9.267;
01131 
01132     // left
01133     cairo_line_to(cr, _align(xt), _align(yt + height));
01134     yt += height;
01135 
01136     // bottom left
01137     cairo_curve_to(cr, _align(xt + 0.103),
01138                    _align(yt + 4.355),
01139                    _align(xt + 1.037),
01140                    _align(yt + 7.444),
01141                    _align(xt + 2.811),
01142                    _align(yt + 9.267));
01143     xt += 2.811;
01144     yt += 9.267;
01145     cairo_curve_to(cr, _align(xt + 1.772),
01146                    _align(yt + 1.823),
01147                    _align(xt + 4.531),
01148                    _align(yt + 2.735),
01149                    _align(xt + 8.28),
01150                    _align(yt + 2.735));
01151     xt += 8.28 + width + 8.279 + 2.811;
01152     yt += 2.735;
01153 
01154     // bottom
01155     cairo_line_to(cr, _align(xt), _align(yt));
01156 
01157     cairo_close_path(cr);
01158     break;
01159 
01160   case Segment::MIDDLE:
01161     yt -= (9.267 + 2.735);
01162     cairo_move_to(cr, _align(xt), _align(yt));
01163     xt -= (2.811 + 8.28);
01164 
01165     // top
01166     cairo_line_to(cr, _align(xt - width - 8.279 - 2.811), _align(yt));
01167 
01168     // top left
01169     xt -= width;
01170     xt -= 8.279;
01171     yt += 2.735;
01172     xt -= 2.811;
01173     yt += 9.267 + height + 2.735 + 9.267;
01174 
01175     // left
01176     cairo_line_to(cr, _align(xt), _align(yt));
01177 
01178     // bottom left
01179     xt += 2.811;
01180     xt += 8.28 + width + 8.279 + 2.811;
01181     // bottom
01182     cairo_line_to(cr, _align(xt), _align(yt));
01183 
01184     cairo_close_path(cr);
01185     break;
01186 
01187   case Segment::RIGHT:
01188     // top right
01189     cairo_move_to(cr, _align(xt), _align(yt));
01190     cairo_curve_to(cr, _align(xt - 0.103),
01191                    _align(yt - 4.355),
01192                    _align(xt - 1.037),
01193                    _align(yt - 7.444),
01194                    _align(xt - 2.811),
01195                    _align(yt - 9.267));
01196     xt -= 2.811;
01197     yt -= 9.267;
01198     cairo_curve_to(cr, _align(xt - 1.722),
01199                    _align(yt - 1.823),
01200                    _align(xt - 4.531),
01201                    _align(yt - 2.735),
01202                    _align(xt - 8.28),
01203                    _align(yt - 2.735));
01204     xt -= (8.28 + width + 8.279 + 2.811);
01205     yt -= 2.735;
01206 
01207     // top
01208     cairo_line_to(cr, _align(xt), _align(yt));
01209 
01210     // left
01211     yt += 9.267 + 2.735 + height + 2.735 + 9.267;
01212     cairo_line_to(cr, _align(xt), _align(yt));
01213 
01214     // bottom left
01215     xt += 2.811 + 8.28;
01216 
01217     // bottom
01218     cairo_line_to(cr, _align(xt + width), _align(yt));
01219     xt += width;
01220 
01221     // bottom right
01222     cairo_curve_to(cr, _align(xt + 3.748),
01223                    _align(yt),
01224                    _align(xt + 6.507),
01225                    _align(yt - 0.912),
01226                    _align(xt + 8.279),
01227                    _align(yt - 2.735));
01228     xt += 8.279;
01229     yt -= 2.735;
01230     cairo_curve_to(cr, _align(xt + 1.773),
01231                    _align(yt - 1.822),
01232                    _align(xt + 2.708),
01233                    _align(yt - 4.911),
01234                    _align(xt + 2.811),
01235                    _align(yt - 9.267));
01236 
01237     cairo_close_path(cr);
01238     break;
01239   }
01240 }
01241 
01242 void Style::Impl::GetTextExtents(int& width,
01243                                      int& height,
01244                                      int  maxWidth,
01245                                      int  maxHeight,
01246                                      std::string const& text)
01247 {
01248   cairo_surface_t*      surface  = NULL;
01249   cairo_t*              cr       = NULL;
01250   PangoLayout*          layout   = NULL;
01251   PangoFontDescription* desc     = NULL;
01252   PangoContext*         pangoCtx = NULL;
01253   PangoRectangle        inkRect  = {0, 0, 0, 0};
01254   int                   dpi      = 0;
01255   char*                 fontName = NULL;
01256   GdkScreen*            screen   = gdk_screen_get_default();  // is not ref'ed
01257   GtkSettings*          settings = gtk_settings_get_default();// is not ref'ed
01258 
01259   surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1);
01260   cr = cairo_create(surface);
01261   if (!screen)
01262     cairo_set_font_options(cr, default_font_options_);
01263   else
01264     cairo_set_font_options(cr, gdk_screen_get_font_options(screen));
01265   layout = pango_cairo_create_layout(cr);
01266 
01267   g_object_get(settings, "gtk-font-name", &fontName, NULL);
01268   if (!fontName)
01269     desc = pango_font_description_from_string("Sans 10");
01270   else
01271   {
01272     desc = pango_font_description_from_string(fontName);
01273     g_free(fontName);
01274   }
01275 
01276   pango_layout_set_font_description(layout, desc);
01277   pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
01278   pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
01279   pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
01280 
01281   pango_layout_set_markup(layout, text.c_str(), -1);
01282   pango_layout_set_height(layout, maxHeight);
01283   pango_layout_set_width(layout, maxWidth * PANGO_SCALE);
01284 
01285   pangoCtx = pango_layout_get_context(layout);  // is not ref'ed
01286 
01287   if (!screen)
01288     pango_cairo_context_set_font_options(pangoCtx, default_font_options_);
01289   else
01290     pango_cairo_context_set_font_options(pangoCtx,
01291                                          gdk_screen_get_font_options(screen));
01292 
01293   g_object_get(settings, "gtk-xft-dpi", &dpi, NULL);
01294   if (dpi == -1)
01295   {
01296     // use some default DPI-value
01297     pango_cairo_context_set_resolution(pangoCtx, 96.0f);
01298   }
01299   else
01300   {
01301     pango_cairo_context_set_resolution(pangoCtx,
01302                                        (float) dpi / (float) PANGO_SCALE);
01303   }
01304   pango_layout_context_changed(layout);
01305   pango_layout_get_extents(layout, &inkRect, NULL);
01306 
01307   width  = inkRect.width / PANGO_SCALE;
01308   height = inkRect.height / PANGO_SCALE;
01309 
01310   // clean up
01311   pango_font_description_free(desc);
01312   g_object_unref(layout);
01313   cairo_destroy(cr);
01314   cairo_surface_destroy(surface);
01315 }
01316 
01317 void Style::Impl::Text(cairo_t*    cr,
01318                        nux::Color const&  color,
01319                        std::string const& label,
01320                        int text_size,
01321                        double horizMargin,
01322                        Alignment alignment)
01323 {
01324   double                x           = 0.0;
01325   double                y           = 0.0;
01326   int                   w           = 0;
01327   int                   h           = 0;
01328   PangoLayout*          layout      = NULL;
01329   PangoFontDescription* desc        = NULL;
01330   PangoContext*         pangoCtx    = NULL;
01331   int                   dpi         = 0;
01332   GdkScreen*            screen      = gdk_screen_get_default();   // not ref'ed
01333   GtkSettings*          settings    = gtk_settings_get_default(); // not ref'ed
01334   gchar*                fontName    = NULL;
01335   //double                horizMargin = 10.0;
01336 
01337   w = cairo_image_surface_get_width(cairo_get_target(cr));
01338   h = cairo_image_surface_get_height(cairo_get_target(cr));
01339 
01340   w -= 2 * horizMargin;
01341 
01342   if (!screen)
01343     cairo_set_font_options(cr, default_font_options_);
01344   else
01345     cairo_set_font_options(cr, gdk_screen_get_font_options(screen));
01346   layout = pango_cairo_create_layout(cr);
01347 
01348   g_object_get(settings, "gtk-font-name", &fontName, NULL);
01349   if (!fontName)
01350     desc = pango_font_description_from_string("Sans 10");
01351   else
01352     desc = pango_font_description_from_string(fontName);
01353 
01354   if (text_size > 0)
01355   {
01356     pango_font_description_set_absolute_size(desc, text_size * PANGO_SCALE);
01357   }
01358 
01359   PangoWeight weight;
01360   switch (regular_text_weight_)
01361   {
01362   case FontWeight::REGULAR:
01363     weight = PANGO_WEIGHT_NORMAL;
01364     break;
01365 
01366   case FontWeight::LIGHT:
01367     weight = PANGO_WEIGHT_LIGHT;
01368     break;
01369 
01370   case FontWeight::BOLD:
01371     weight = PANGO_WEIGHT_BOLD;
01372     break;
01373   }
01374   pango_font_description_set_weight(desc, weight);
01375 
01376   pango_layout_set_font_description(layout, desc);
01377   pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
01378   pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
01379 
01380   PangoAlignment pango_alignment = PANGO_ALIGN_LEFT;
01381   switch (alignment)
01382   {
01383   case Alignment::LEFT:
01384     pango_alignment = PANGO_ALIGN_LEFT;
01385     break;
01386 
01387   case Alignment::CENTER:
01388     pango_alignment = PANGO_ALIGN_CENTER;
01389     break;
01390 
01391   case Alignment::RIGHT:
01392     pango_alignment = PANGO_ALIGN_RIGHT;
01393     break;
01394   }
01395   pango_layout_set_alignment(layout, pango_alignment);
01396 
01397   pango_layout_set_markup(layout, label.c_str(), -1);
01398   pango_layout_set_width(layout, w * PANGO_SCALE);
01399 
01400   pango_layout_set_height(layout, h);
01401   pangoCtx = pango_layout_get_context(layout);  // is not ref'ed
01402 
01403   if (!screen)
01404     pango_cairo_context_set_font_options(pangoCtx, default_font_options_);
01405   else
01406     pango_cairo_context_set_font_options(pangoCtx,
01407                                          gdk_screen_get_font_options(screen));
01408 
01409   g_object_get(settings, "gtk-xft-dpi", &dpi, NULL);
01410   if (dpi == -1)
01411   {
01412     // use some default DPI-value
01413     pango_cairo_context_set_resolution(pangoCtx, 96.0f);
01414   }
01415   else
01416   {
01417     pango_cairo_context_set_resolution(pangoCtx,
01418                                        (float) dpi / (float) PANGO_SCALE);
01419   }
01420 
01421   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
01422   cairo_set_source_rgba(cr, color);
01423   pango_layout_context_changed(layout);
01424   PangoRectangle ink = {0, 0, 0, 0};
01425   PangoRectangle log = {0, 0, 0, 0};
01426   pango_layout_get_extents(layout, &ink, &log);
01427   x = horizMargin; // let pango alignment handle the x position
01428   y = ((double) h - pango_units_to_double(log.height)) / 2.0;
01429 
01430   cairo_move_to(cr, x, y);
01431   pango_cairo_show_layout(cr, layout);
01432 
01433   // clean up
01434   pango_font_description_free(desc);
01435   g_object_unref(layout);
01436   g_free(fontName);
01437 }
01438 
01439 cairo_operator_t Style::Impl::SetBlendMode(cairo_t* cr, BlendMode mode)
01440 {
01441   // sanity checks
01442   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01443     return CAIRO_OPERATOR_OVER;
01444 
01445   cairo_operator_t old;
01446 
01447   old = cairo_get_operator(cr);
01448 
01449   if (mode == BlendMode::NORMAL)
01450     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
01451   else if (mode == BlendMode::MULTIPLY)
01452     cairo_set_operator(cr, CAIRO_OPERATOR_MULTIPLY);
01453   else if (mode == BlendMode::SCREEN)
01454     cairo_set_operator(cr, CAIRO_OPERATOR_SCREEN);
01455 
01456   return old;
01457 }
01458 
01459 void Style::Impl::DrawOverlay(cairo_t*  cr,
01460                                   double    opacity,
01461                                   BlendMode mode,
01462                                   int       blurSize)
01463 {
01464   // sanity checks
01465   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS ||
01466       opacity <= 0.0                            ||
01467       blurSize <= 0)
01468     return;
01469 
01470   cairo_surface_t*     target     = NULL;
01471   const unsigned char* data       = NULL;
01472   int                  width      = 0;
01473   int                  height     = 0;
01474   int                  stride     = 0;
01475   cairo_format_t       format     = CAIRO_FORMAT_INVALID;
01476   unsigned char*       buffer     = NULL;
01477   cairo_surface_t*     surface    = NULL;
01478   cairo_t*             blurred_cr = NULL;
01479   cairo_operator_t     old        = CAIRO_OPERATOR_CLEAR;
01480 
01481   // aquire info about image-surface
01482   target = cairo_get_target(cr);
01483   data   = cairo_image_surface_get_data(target);
01484   width  = cairo_image_surface_get_width(target);
01485   height = cairo_image_surface_get_height(target);
01486   stride = cairo_image_surface_get_stride(target);
01487   format = cairo_image_surface_get_format(target);
01488 
01489   // get buffer
01490   buffer = (unsigned char*) calloc(1, height * stride);
01491   if (!buffer)
01492     return;
01493 
01494   // copy initial image-surface
01495   memcpy(buffer, data, height * stride);
01496   surface = cairo_image_surface_create_for_data(buffer,
01497                                                 format,
01498                                                 width,
01499                                                 height,
01500                                                 stride);
01501   if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
01502   {
01503     cairo_surface_destroy(surface);
01504     free(buffer);
01505     return;
01506   }
01507 
01508   // prepare context
01509   blurred_cr = cairo_create(surface);
01510   if (cairo_status(blurred_cr) != CAIRO_STATUS_SUCCESS)
01511   {
01512     cairo_destroy(blurred_cr);
01513     cairo_surface_destroy(surface);
01514     free(buffer);
01515     return;
01516   }
01517 
01518   // blur and blend overlay onto initial image-surface
01519   Blur(blurred_cr, blurSize);
01520   //cairo_surface_write_to_png(surface, "/tmp/overlay-surface.png");
01521   cairo_set_source_surface(cr, surface, 0.0, 0.0);
01522   old = SetBlendMode(cr, mode);
01523   cairo_paint_with_alpha(cr, opacity);
01524 
01525   // clean up
01526   cairo_destroy(blurred_cr);
01527   cairo_surface_destroy(surface);
01528   free(buffer);
01529   cairo_set_operator(cr, old);
01530 }
01531 
01532 bool Style::Button(cairo_t* cr, nux::ButtonVisualState state,
01533                    std::string const& label, int font_size,
01534                    Alignment alignment, bool zeromargin)
01535 {
01536   // sanity checks
01537   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01538     return false;
01539 
01540   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01541     return false;
01542 
01543   unsigned int garnish = 0;
01544   if (zeromargin == false)
01545    garnish = GetButtonGarnishSize();
01546 
01547   //ButtonOutlinePath(cr, true);
01548   double w = cairo_image_surface_get_width(cairo_get_target(cr));
01549   double h = cairo_image_surface_get_height(cairo_get_target(cr));
01550 
01551   cairo_set_line_width(cr, pimpl->button_label_border_size_[state]);
01552 
01553   if (pimpl->button_label_border_size_[state] == 2.0)
01554     RoundedRect(cr,
01555                 1.0,
01556                 (double) (garnish) + 1.0,
01557                 (double) (garnish) + 1.0,
01558                 7.0,
01559                 w - (double) (2 * garnish) - 2.0,
01560                 h - (double) (2 * garnish) - 2.0);
01561   else
01562     RoundedRect(cr,
01563                 1.0,
01564                 (double) (garnish) + 0.5,
01565                 (double) (garnish) + 0.5,
01566                 7.0,
01567                 w - (double) (2 * garnish) - 1.0,
01568                 h - (double) (2 * garnish) - 1.0);
01569 
01570 
01571   if (pimpl->button_label_fill_color_[state].alpha != 0.0)
01572   {
01573     cairo_set_source_rgba(cr, pimpl->button_label_fill_color_[state]);
01574     cairo_fill_preserve(cr);
01575   }
01576   cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]);
01577   cairo_stroke(cr);
01578 
01579   pimpl->DrawOverlay(cr,
01580                      pimpl->button_label_overlay_opacity_[state],
01581                      pimpl->button_label_overlay_mode_[state],
01582                      pimpl->button_label_blur_size_[state] * 0.75);
01583 
01584   pimpl->Text(cr,
01585               pimpl->button_label_text_color_[state],
01586               label,
01587               font_size,
01588               11.0, // 15px = 11pt
01589               alignment);
01590 
01591   return true;
01592 }
01593 
01594 nux::AbstractPaintLayer* Style::FocusOverlay(int width, int height)
01595 {
01596   nux::CairoGraphics cg(CAIRO_FORMAT_ARGB32, width, height);
01597   cairo_t* cr = cg.GetInternalContext();
01598 
01599   RoundedRect(cr,
01600               1.0f,
01601               0.0f,
01602               0.0f,
01603               2.0f, // radius
01604               width,
01605               height);
01606 
01607   cairo_set_source_rgba(cr, nux::Color(1.0f, 1.0f, 1.0f, 0.2f));
01608   cairo_fill(cr);
01609 
01610   // Create the texture layer
01611   nux::TexCoordXForm texxform;
01612 
01613   nux::ROPConfig rop;
01614   rop.Blend = true;
01615   rop.SrcBlend = GL_ONE;
01616   rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
01617 
01618   return (new nux::TextureLayer(texture_ptr_from_cairo_graphics(cg)->GetDeviceTexture(),
01619                                 texxform,
01620                                 nux::color::White,
01621                                 false,
01622                                 rop));
01623 }
01624 
01625 bool Style::SquareButton(cairo_t* cr, nux::ButtonVisualState state,
01626                          std::string const& label, bool curve_bottom,
01627                          int font_size, Alignment alignment,
01628                          bool zeromargin)
01629 {
01630   // sanity checks
01631   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01632     return false;
01633 
01634   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01635     return false;
01636 
01637   unsigned int garnish = 0;
01638   if (zeromargin == false)
01639     garnish = GetButtonGarnishSize();
01640 
01641   double w = cairo_image_surface_get_width(cairo_get_target(cr));
01642   double h = cairo_image_surface_get_height(cairo_get_target(cr));
01643 
01644   double x = garnish;
01645   double y = garnish;
01646 
01647   double width = w - (2.0 * garnish) - 1.0;
01648   double height = h - (2.0 * garnish) - 1.0;
01649 
01650   bool odd = true;
01651   double radius = 7.0;
01652 
01653   // draw the grid background
01654   {
01655     cairo_set_line_width(cr, 1);
01656     cairo_move_to(cr, _align(x + width, odd), y);
01657     if (curve_bottom)
01658     {
01659       LOG_DEBUG(logger) << "curve: " << _align(x + width, odd) << " - " << _align(y + height - radius, odd);
01660       // line to bottom-right corner
01661       cairo_line_to(cr, _align(x + width, odd), _align(y + height - radius, odd));
01662 
01663       // line to bottom-right, left of the corner
01664       cairo_arc(cr,
01665                 _align(x + width - radius, odd),
01666                 _align(y + height - radius, odd),
01667                 radius,
01668                 0.0f * G_PI / 180.0f,
01669                 90.0f * G_PI / 180.0f);
01670 
01671       // line to bottom-left, right of the corner
01672       cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd));
01673 
01674       // line to bottom-left, above the corner
01675       cairo_arc(cr,
01676                 _align(x + radius, odd),
01677                 _align(y + height - radius, odd),
01678                 radius,
01679                 90.0f * G_PI / 180.0f,
01680                 180.0f * G_PI / 180.0f);
01681 
01682       // line to top
01683       cairo_line_to(cr, _align(x, odd), _align(y, odd));
01684     }
01685     else
01686     {
01687       cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
01688       cairo_line_to(cr, _align(x, odd), _align(y + height, odd));
01689       cairo_line_to(cr, _align(x, odd), y);
01690     }
01691 
01692     cairo_set_source_rgba(cr, pimpl->button_label_border_color_[nux::ButtonVisualState::VISUAL_STATE_NORMAL]);
01693     cairo_stroke(cr);
01694   }
01695 
01696   cairo_set_line_width(cr, pimpl->button_label_border_size_[state]);
01697   odd = cairo_get_line_width(cr) == 2.0 ? false : true;
01698 
01699 
01700   if (pimpl->button_label_border_size_[state] == 2.0)
01701   {
01702     x += 1;
01703     y += 1;
01704     width -= 1.0;
01705     height -= 1.0;
01706   }
01707 
01708   if (state == nux::ButtonVisualState::VISUAL_STATE_PRESSED)
01709   {
01710     RoundedRect(cr,
01711                 1.0,
01712                 _align(x, odd), _align(y, odd),
01713                 5.0,
01714                 _align(width, odd), _align(height, odd));
01715 
01716     if (pimpl->button_label_fill_color_[state].alpha != 0.0)
01717     {
01718       cairo_set_source_rgba(cr, pimpl->button_label_fill_color_[state]);
01719       cairo_fill_preserve(cr);
01720     }
01721     cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]);
01722     cairo_stroke(cr);
01723   }
01724 
01725   pimpl->DrawOverlay(cr,
01726                      pimpl->button_label_overlay_opacity_[state],
01727                      pimpl->button_label_overlay_mode_[state],
01728                      pimpl->button_label_blur_size_[state] * 0.75);
01729 
01730   // FIXME - magic value of 42 here for the offset in the HUD,
01731   // replace with a nicer style system that lets hud override
01732   // default values when it needs to
01733   pimpl->Text(cr,
01734               pimpl->button_label_text_color_[state],
01735               label,
01736               font_size,
01737               42.0 + 10.0,
01738               alignment);
01739 
01740   cairo_surface_write_to_png(cairo_get_target(cr), "/tmp/wut.png");
01741 
01742   return true;
01743 }
01744 
01745 bool Style::ButtonFocusOverlay(cairo_t* cr)
01746 {
01747   // sanity checks
01748   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01749     return false;
01750 
01751   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01752     return false;
01753 
01754   double w = cairo_image_surface_get_width(cairo_get_target(cr));
01755   double h = cairo_image_surface_get_height(cairo_get_target(cr));
01756 
01757   nux::Color color(nux::color::White);
01758   color.alpha = 0.50f;
01759   cairo_set_line_width(cr, pimpl->button_label_border_size_[nux::VISUAL_STATE_NORMAL]);
01760 
01761   RoundedRect(cr,
01762               1.0,
01763               (double) 0.5,
01764               (double) 0.5,
01765               7.0,
01766               w - 1.0,
01767               h - 1.0);
01768 
01769   cairo_set_source_rgba(cr, color);
01770   cairo_fill_preserve(cr);
01771   cairo_stroke(cr);
01772 
01773   return true;
01774 }
01775 
01776 bool Style::MultiRangeSegment(cairo_t*    cr,
01777                               nux::ButtonVisualState  state,
01778                               std::string const& label,
01779                               Arrow       arrow,
01780                               Segment     segment)
01781 {
01782   // sanity checks
01783   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01784     return false;
01785 
01786   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01787     return false;
01788 
01789   //ButtonOutlinePathSegment(cr, segment);
01790   double   x  = 0.0;
01791   double   y  = 2.0;
01792   double   w  = cairo_image_surface_get_width(cairo_get_target(cr));
01793   double   h  = cairo_image_surface_get_height(cairo_get_target(cr)) - 4.0;
01794 
01795        if (segment == Segment::LEFT)
01796        {
01797     x = 2.0;
01798     w -= 2.0;
01799        }
01800 
01801        if (segment == Segment::RIGHT)
01802        {
01803     w -= 2.0;
01804        }
01805 
01806   cairo_set_line_width(cr, pimpl->button_label_border_size_[state]);
01807 
01808   if (pimpl->button_label_border_size_[state] == 2.0)
01809     pimpl->RoundedRectSegment(cr,
01810                               1.0,
01811                               x+1.0,
01812                               y+1.0,
01813                               (h-1.0) / 4.0,
01814                               w-1.0,
01815                               h-1.0,
01816                               segment,
01817                               arrow,
01818                               state);
01819   else
01820     pimpl->RoundedRectSegment(cr,
01821                               1.0,
01822                               x,
01823                               y,
01824                               h / 4.0,
01825                               w,
01826                               h,
01827                               segment,
01828                               arrow,
01829                               state);
01830 
01831   if (pimpl->button_label_fill_color_[state].alpha != 0.0)
01832   {
01833     cairo_set_source_rgba(cr, pimpl->button_label_fill_color_[state]);
01834     cairo_fill_preserve(cr);
01835   }
01836   cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]);
01837   cairo_stroke(cr);
01838   pimpl->Text(cr,
01839               pimpl->button_label_text_color_[state],
01840               label,
01841               10); // 13px = 10pt
01842 
01843   return true;
01844 }
01845 
01846 bool Style::MultiRangeFocusOverlay(cairo_t* cr,
01847                                    Arrow arrow,
01848                                    Segment segment)
01849 {
01850   // sanity checks
01851   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01852     return false;
01853 
01854   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01855     return false;
01856 
01857   double   x  = 0.0;
01858   double   y  = 2.0;
01859   double   w  = cairo_image_surface_get_width(cairo_get_target(cr));
01860   double   h  = cairo_image_surface_get_height(cairo_get_target(cr)) - 4.0;
01861 
01862   if (segment == Segment::LEFT)
01863   {
01864     x = 2.0;
01865     w -= 2.0;
01866   }
01867 
01868   if (segment == Segment::RIGHT)
01869   {
01870     w -= 2.0;
01871   }
01872 
01873   cairo_set_line_width(cr, pimpl->button_label_border_size_[nux::ButtonVisualState::VISUAL_STATE_NORMAL]);
01874 
01875   pimpl->RoundedRectSegment(cr,
01876                             1.0,
01877                             x,
01878                             y,
01879                             h / 4.0,
01880                             w,
01881                             h,
01882                             segment,
01883                             arrow,
01884                             nux::ButtonVisualState::VISUAL_STATE_PRESSED);
01885 
01886   cairo_set_source_rgba(cr, nux::Color(1.0f, 1.0f, 1.0f, 0.5f));
01887   cairo_fill_preserve(cr);
01888   cairo_stroke(cr);
01889 
01890   return true;
01891 }
01892 
01893 bool Style::TrackViewNumber(cairo_t*    cr,
01894                             nux::ButtonVisualState state,
01895                             std::string const& trackNumber)
01896 {
01897   // sanity checks
01898   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01899     return false;
01900 
01901   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01902     return false;
01903 
01904   return true;
01905 }
01906 
01907 bool Style::TrackViewPlay(cairo_t*   cr,
01908                           nux::ButtonVisualState state)
01909 {
01910   // sanity checks
01911   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01912     return false;
01913 
01914   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01915     return false;
01916 
01917   return true;
01918 }
01919 
01920 bool Style::TrackViewPause(cairo_t*   cr,
01921                            nux::ButtonVisualState state)
01922 {
01923   // sanity checks
01924   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01925     return false;
01926 
01927   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01928     return false;
01929 
01930   return true;
01931 }
01932 
01933 bool Style::TrackViewProgress(cairo_t* cr)
01934 {
01935   // sanity checks
01936   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01937     return false;
01938 
01939   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01940     return false;
01941 
01942   return true;
01943 }
01944 
01945 bool Style::SeparatorVert(cairo_t* cr)
01946 {
01947   // sanity checks
01948   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01949     return false;
01950 
01951   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01952     return false;
01953 
01954   double w = cairo_image_surface_get_width(cairo_get_target(cr));
01955   double h = cairo_image_surface_get_height(cairo_get_target(cr));
01956   double x = w / 2.0;
01957   double y = 2.0;
01958 
01959   cairo_set_line_width(cr, pimpl->separator_size_);
01960   cairo_set_source_rgba(cr, pimpl->separator_color_);
01961   cairo_move_to(cr, _align(x), _align(y));
01962   cairo_line_to(cr, _align(x), _align(h - 4.0));
01963   cairo_stroke(cr);
01964 
01965   pimpl->DrawOverlay(cr,
01966                      pimpl->separator_overlay_opacity_,
01967                      pimpl->separator_overlay_mode_,
01968                      pimpl->separator_blur_size_);
01969 
01970   return true;
01971 }
01972 
01973 bool Style::SeparatorHoriz(cairo_t* cr)
01974 {
01975   // sanity checks
01976   if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
01977     return false;
01978 
01979   if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
01980     return false;
01981 
01982   double w = cairo_image_surface_get_width(cairo_get_target(cr));
01983   double h = cairo_image_surface_get_height(cairo_get_target(cr));
01984   double x = 2.0;
01985   double y = h / 2.0;
01986 
01987   cairo_set_line_width(cr, pimpl->separator_size_);
01988   cairo_set_source_rgba(cr, pimpl->separator_color_);
01989   cairo_move_to(cr, _align(x), _align(y));
01990   cairo_line_to(cr, _align(w - 4.0), _align(y));
01991   cairo_stroke(cr);
01992 
01993   pimpl->DrawOverlay(cr,
01994                      pimpl->separator_overlay_opacity_,
01995                      pimpl->separator_overlay_mode_,
01996                      pimpl->separator_blur_size_);
01997 
01998   return true;
01999 }
02000 
02001 int Style::GetButtonGarnishSize()
02002 {
02003   int maxBlurSize = 0;
02004 
02005   for (int i = 0; i < STATES; i++)
02006   {
02007     if (maxBlurSize < pimpl->button_label_blur_size_[i])
02008       maxBlurSize = pimpl->button_label_blur_size_[i];
02009   }
02010 
02011   return 2 * maxBlurSize;
02012 }
02013 
02014 int Style::GetSeparatorGarnishSize()
02015 {
02016   return pimpl->separator_blur_size_;
02017 }
02018 
02019 int Style::GetScrollbarGarnishSize()
02020 {
02021   return pimpl->scrollbar_blur_size_;
02022 }
02023 
02024 nux::Color const& Style::GetTextColor() const
02025 {
02026   return pimpl->text_color_;
02027 }
02028 
02029 int  Style::GetDefaultNColumns() const
02030 {
02031   return pimpl->number_of_columns_;
02032 }
02033 
02034 void Style::SetDefaultNColumns(int n_cols)
02035 {
02036   if (pimpl->number_of_columns_ == n_cols)
02037     return;
02038 
02039   pimpl->number_of_columns_ = n_cols;
02040 
02041   columns_changed.emit();
02042 }
02043 
02044 int Style::GetTileIconSize() const
02045 {
02046   return 64;
02047 }
02048 
02049 int Style::GetTileWidth() const
02050 {
02051   return std::max(pimpl->text_width_, 150);
02052 }
02053 
02054 int Style::GetTileHeight() const
02055 {
02056   return std::max(GetTileIconSize() + (pimpl->text_height_ * 2) + 10,
02057                   GetTileIconSize() + 50 + 18); // magic design numbers.
02058 }
02059 
02060 int Style::GetHomeTileIconSize() const
02061 {
02062   return 104;
02063 }
02064 
02065 int Style::GetHomeTileWidth() const
02066 {
02067   return pimpl->text_width_ * 1.2;
02068 }
02069 
02070 int Style::GetHomeTileHeight() const
02071 {
02072   return GetHomeTileIconSize() + (pimpl->text_height_ * 5);
02073 }
02074 
02075 int Style::GetTextLineHeight() const
02076 {
02077   return pimpl->text_height_;
02078 }
02079 
02080 
02081 nux::BaseTexture* Style::GetDashBottomTile()
02082 {
02083   return pimpl->dash_bottom_texture_.texture();
02084 }
02085 
02086 nux::BaseTexture* Style::GetDashBottomTileMask()
02087 {
02088   return pimpl->dash_bottom_texture_mask_.texture();
02089 }
02090 
02091 nux::BaseTexture* Style::GetDashRightTile()
02092 {
02093   return pimpl->dash_right_texture_.texture();
02094 }
02095 
02096 nux::BaseTexture* Style::GetDashRightTileMask()
02097 {
02098   return pimpl->dash_right_texture_mask_.texture();
02099 }
02100 
02101 nux::BaseTexture* Style::GetDashCorner()
02102 {
02103   return pimpl->dash_corner_texture_.texture();
02104 }
02105 
02106 nux::BaseTexture* Style::GetDashCornerMask()
02107 {
02108   return pimpl->dash_corner_texture_mask_.texture();
02109 }
02110 
02111 nux::BaseTexture* Style::GetDashLeftEdge()
02112 {
02113   return pimpl->dash_left_edge_.texture();
02114 }
02115 
02116 nux::BaseTexture* Style::GetDashLeftCorner()
02117 {
02118   return pimpl->dash_left_corner_.texture();
02119 }
02120 
02121 nux::BaseTexture* Style::GetDashLeftCornerMask()
02122 {
02123   return pimpl->dash_left_corner_mask_.texture();
02124 }
02125 
02126 nux::BaseTexture* Style::GetDashLeftTile()
02127 {
02128   return pimpl->dash_left_tile_.texture();
02129 }
02130 
02131 nux::BaseTexture* Style::GetDashTopCorner()
02132 {
02133   return pimpl->dash_top_corner_.texture();
02134 }
02135 
02136 nux::BaseTexture* Style::GetDashTopCornerMask()
02137 {
02138   return pimpl->dash_top_corner_mask_.texture();
02139 }
02140 
02141 nux::BaseTexture* Style::GetDashTopTile()
02142 {
02143   return pimpl->dash_top_tile_.texture();
02144 }
02145 
02146 nux::BaseTexture* Style::GetDashFullscreenIcon()
02147 {
02148   return pimpl->dash_fullscreen_icon_.texture();
02149 }
02150 
02151 nux::BaseTexture* Style::GetSearchMagnifyIcon()
02152 {
02153   return pimpl->search_magnify_texture_.texture();
02154 }
02155 
02156 nux::BaseTexture* Style::GetSearchCircleIcon()
02157 {
02158   return pimpl->search_circle_texture_.texture();
02159 }
02160 
02161 nux::BaseTexture* Style::GetSearchCloseIcon()
02162 {
02163   return pimpl->search_close_texture_.texture();
02164 }
02165 
02166 nux::BaseTexture* Style::GetSearchSpinIcon()
02167 {
02168   return pimpl->search_spin_texture_.texture();
02169 }
02170 
02171 nux::BaseTexture* Style::GetGroupUnexpandIcon()
02172 {
02173   return pimpl->group_unexpand_texture_.texture();
02174 }
02175 
02176 nux::BaseTexture* Style::GetGroupExpandIcon()
02177 {
02178   return pimpl->group_expand_texture_.texture();
02179 }
02180 
02181 nux::BaseTexture* Style::GetStarDeselectedIcon()
02182 {
02183   return pimpl->star_deselected_texture_.texture();
02184 }
02185 
02186 nux::BaseTexture* Style::GetStarSelectedIcon()
02187 {
02188   return pimpl->star_selected_texture_.texture();
02189 }
02190 
02191 nux::BaseTexture* Style::GetStarHighlightIcon()
02192 {
02193   return pimpl->star_highlight_texture_.texture();
02194 }
02195 
02196 nux::BaseTexture* Style::GetDashShine()
02197 {
02198   return pimpl->dash_shine_.texture();
02199 }
02200 
02201 int Style::GetDashBottomTileHeight() const
02202 {
02203   return 30;
02204 }
02205 
02206 int Style::GetDashRightTileWidth() const
02207 {
02208   return 30;
02209 }
02210 
02211 int Style::GetVSeparatorSize() const
02212 {
02213   return 1;
02214 }
02215 
02216 int Style::GetHSeparatorSize() const
02217 {
02218   return 1;
02219 
02220 }
02221 
02222 int Style::GetFilterBarWidth() const
02223 {
02224   return 300;
02225 }
02226 
02227 
02228 int Style::GetFilterBarLeftPadding() const
02229 {
02230   return 5;
02231 }
02232 
02233 int Style::GetFilterBarRightPadding() const
02234 {
02235   return 5;
02236 }
02237 
02238 int Style::GetDashViewTopPadding() const
02239 {
02240   return 10;
02241 }
02242 
02243 int Style::GetSearchBarLeftPadding() const
02244 {
02245   return 10;
02246 }
02247 
02248 int Style::GetSearchBarRightPadding() const
02249 {
02250   return 10;
02251 }
02252 
02253 int Style::GetSearchBarHeight() const
02254 {
02255   return 42;
02256 }
02257 
02258 int Style::GetFilterResultsHighlightRightPadding() const
02259 {
02260   return 5;
02261 }
02262 
02263 int Style::GetFilterResultsHighlightLeftPadding() const
02264 {
02265   return 5;
02266 }
02267 
02268 int Style::GetFilterBarTopPadding() const
02269 {
02270   return 10;
02271 }
02272 
02273 int Style::GetFilterHighlightPadding() const
02274 {
02275   return 2;
02276 }
02277 
02278 int Style::GetSpaceBetweenFilterWidgets() const
02279 {
02280   return 12;
02281 }
02282 
02283 int Style::GetAllButtonHeight() const
02284 {
02285   return 30;
02286 }
02287 
02288 int Style::GetFilterButtonHeight() const
02289 {
02290   return 30;
02291 }
02292 
02293 int Style::GetSpaceBetweenLensAndFilters() const
02294 {
02295   return 10;
02296 }
02297 
02298 int Style::GetFilterViewRightPadding() const
02299 {
02300   return 10;
02301 }
02302 
02303 int Style::GetScrollbarWidth() const
02304 {
02305   return 3;
02306 }
02307 
02308 int Style::GetCategoryHighlightHeight() const
02309 {
02310   return 24;
02311 }
02312 
02313 int Style::GetPlacesGroupTopSpace() const
02314 {
02315   return 15;
02316 }
02317 
02318 int Style::GetCategoryHeaderLeftPadding() const
02319 {
02320   return 20;
02321 }
02322 
02323 int Style::GetCategorySeparatorLeftPadding() const
02324 {
02325   return 15;
02326 }
02327 
02328 int Style::GetCategorySeparatorRightPadding() const
02329 {
02330   return 15;
02331 }
02332 
02333 namespace
02334 {
02335 
02336 LazyLoadTexture::LazyLoadTexture(std::string const& filename, int size)
02337   : filename_(filename)
02338   , size_(size)
02339 {
02340 }
02341 
02342 nux::BaseTexture* LazyLoadTexture::texture()
02343 {
02344   if (!texture_)
02345     LoadTexture();
02346   return texture_.GetPointer();
02347 }
02348 
02349 void LazyLoadTexture::LoadTexture()
02350 {
02351   std::string full_path = PKGDATADIR + filename_;
02352   glib::Object<GdkPixbuf> pixbuf;
02353   glib::Error error;
02354 
02355   pixbuf = ::gdk_pixbuf_new_from_file_at_size(full_path.c_str(), size_, size_, &error);
02356   if (error)
02357   {
02358     LOG_WARN(logger) << "Unable to texture " << full_path << ": " << error;
02359   }
02360   else
02361   {
02362     texture_.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true));
02363   }
02364 }
02365 
02366 } // anon namespace
02367 
02368 } // namespace dash
02369 } // namespace unity