text: #include "deco-theme.hpp"
  #include <wayfire/core.hpp>
  #include <wayfire/opengl.hpp>
  #include <config.h>
  #include <map>
  
  namespace wf
  {
  namespace decor
  {
  /** Create a new theme with the default parameters */
  decoration_theme_t::decoration_theme_t()
  {}
  
  /** @return The available height for displaying the title */
  int decoration_theme_t::get_title_height() const
  {
      return title_height;
  }
  
  /** @return The available border for resizing */
  int decoration_theme_t::get_border_size() const
  {
      return border_size;
  }
  
  /**
   * Fill the given rectange with the background color(s).
   *
   * @param fb The target framebuffer, must have been bound already
   * @param rectangle The rectangle to redraw.
   * @param scissor The GL scissor rectangle to use.
   * @param active Whether to use active or inactive colors
   */
  void decoration_theme_t::render_background(const wf::framebuffer_t& fb,
      wf::geometry_t rectangle, const wf::geometry_t& scissor, bool active) const
  {
      wf::color_t color = active ? active_color : inactive_color;
      OpenGL::render_begin(fb);
      fb.logic_scissor(scissor);
      OpenGL::render_rectangle(rectangle, color, fb.get_orthographic_projection());
      OpenGL::render_end();
  }
  
  /**
   * Render the given text on a cairo_surface_t with the given size.
   * The caller is responsible for freeing the memory afterwards.
   */
  cairo_surface_t*decoration_theme_t::render_text(std::string text,
      int width, int height) const
  {
      const auto format = CAIRO_FORMAT_ARGB32;
      auto surface = cairo_image_surface_create(format, width, height);
      auto cr = cairo_create(surface);
  
      const float font_scale = 0.8;
      const float font_size  = height * font_scale;
  
      // render text
      cairo_select_font_face(cr, ((std::string)font).c_str(),
          CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
      cairo_set_source_rgba(cr, 1, 1, 1, 1);
  
      cairo_set_font_size(cr, font_size);
      cairo_move_to(cr, 0, font_size);
  
      cairo_text_extents_t ext;
      cairo_text_extents(cr, text.c_str(), &ext);
      cairo_show_text(cr, text.c_str());
      cairo_destroy(cr);
  
      return surface;
  }
  
  cairo_surface_t*decoration_theme_t::get_button_surface(button_type_t button,
      const button_state_t& state) const
  {
      cairo_surface_t *button_surface = cairo_image_surface_create(
          CAIRO_FORMAT_ARGB32, state.width, state.height);
  
      auto cr = cairo_create(button_surface);
      cairo_set_antialias(cr, CAIRO_ANTIALIAS_BEST);
  
      /* Clear the button background */
      cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
      cairo_set_source_rgba(cr, 0, 0, 0, 0);
      cairo_rectangle(cr, 0, 0, state.width, state.height);
      cairo_fill(cr);
  
      cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
  
      /** A gray that looks good on light and dark themes */
      color_t base = {0.60, 0.60, 0.63, 0.36};
  
      /**
       * We just need the alpha component.
       * r == g == b == 0.0 will be directly set
       */
      double line  = 0.27;
      double hover = 0.27;
  
      /** Coloured base on hover/press. Don't compare float to 0 */
      if (fabs(state.hover_progress) > 1e-3)
      {
          switch (button)
          {
            case BUTTON_CLOSE:
              base = {242.0 / 255.0, 80.0 / 255.0, 86.0 / 255.0, 0.63};
              break;
  
            case BUTTON_TOGGLE_MAXIMIZE:
              base = {57.0 / 255.0, 234.0 / 255.0, 73.0 / 255.0, 0.63};
              break;
  
            case BUTTON_MINIMIZE:
              base = {250.0 / 255.0, 198.0 / 255.0, 54.0 / 255.0, 0.63};
              break;
  
            default:
              assert(false);
          }
  
          line *= 2.0;
      }
  
      /** Draw the base */
      cairo_set_source_rgba(cr,
          base.r + 0.0 * state.hover_progress,
          base.g + 0.0 * state.hover_progress,
          base.b + 0.0 * state.hover_progress,
          base.a + hover * state.hover_progress);
      cairo_arc(cr, state.width / 2, state.height / 2,
          state.width / 2, 0, 2 * M_PI);
      cairo_fill(cr);
  
      /** Draw the border */
      cairo_set_line_width(cr, state.border);
      cairo_set_source_rgba(cr, 0.00, 0.00, 0.00, line);
      // This renders great on my screen (110 dpi 1376x768 lcd screen)
      // How this would appear on a Hi-DPI screen is questionable
      double r = state.width / 2 - 0.5 * state.border;
      cairo_arc(cr, state.width / 2, state.height / 2, r, 0, 2 * M_PI);
      cairo_stroke(cr);
  
      /** Draw the icon  */
      cairo_set_source_rgba(cr, 0.00, 0.00, 0.00, line / 2);
      cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
      switch (button)
      {
        case BUTTON_CLOSE:
          cairo_set_line_width(cr, 1.5 * state.border);
          cairo_move_to(cr, 1.0 * state.width / 4.0,
              1.0 * state.height / 4.0);
          cairo_line_to(cr, 3.0 * state.width / 4.0,
              3.0 * state.height / 4.0); // '\' part of x
          cairo_move_to(cr, 3.0 * state.width / 4.0,
              1.0 * state.height / 4.0);
          cairo_line_to(cr, 1.0 * state.width / 4.0,
              3.0 * state.height / 4.0); // '/' part of x
          cairo_stroke(cr);
          break;
  
        case BUTTON_TOGGLE_MAXIMIZE:
          cairo_set_line_width(cr, 1.5 * state.border);
          cairo_rectangle(
              cr, // Context
              state.width / 4.0, state.height / 4.0, // (x, y)
              state.width / 2.0, state.height / 2.0 // w x h
          );
          cairo_stroke(cr);
          break;
  
        case BUTTON_MINIMIZE:
          cairo_set_line_width(cr, 1.75 * state.border);
          cairo_move_to(cr, 1.0 * state.width / 4.0,
              state.height / 2.0);
          cairo_line_to(cr, 3.0 * state.width / 4.0,
              state.height / 2.0);
          cairo_stroke(cr);
          break;
  
        default:
          assert(false);
      }
  
      cairo_fill(cr);
      cairo_destroy(cr);
  
      return button_surface;
  }
  }
  }
  