#if defined(Hiro_Label)

namespace hiro {

static auto Label_draw(GtkWidget* widget, cairo_t* context, pLabel* p) -> int {
  auto color = p->state().backgroundColor;
  if(auto window = p->self().parentWindow(true)) {
    if(!color) color = window->backgroundColor();
  }

  if(color) {
    double red   = (double)color.red()   / 255.0;
    double green = (double)color.green() / 255.0;
    double blue  = (double)color.blue()  / 255.0;
    double alpha = (double)color.alpha() / 255.0;

    if(gdk_screen_is_composited(gdk_screen_get_default())
    && gdk_screen_get_rgba_visual(gdk_screen_get_default())
    ) {
      cairo_set_source_rgba(context, red, green, blue, alpha);
    } else {
      cairo_set_source_rgb(context, red, green, blue);
    }

    cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
    cairo_paint(context);
  } else {
    #if HIRO_GTK==3
    auto style = gtk_widget_get_style_context(widget);
    if(auto tabFrame = p->self().parentTabFrame(true)) {
      if(auto self = tabFrame->self()) style = gtk_widget_get_style_context(self->gtkWidget);
    }
    GtkAllocation allocation;
    gtk_widget_get_allocation(widget, &allocation);
    gtk_render_background(style, context, 0, 0, allocation.width, allocation.height);
    #endif
  }

  return false;
}

static auto Label_expose(GtkWidget* widget, GdkEvent* event, pLabel* p) -> int {
  cairo_t* context = gdk_cairo_create(gtk_widget_get_window(widget));
  Label_draw(widget, context, p);
  cairo_destroy(context);
  return false;
}

static auto Label_mouseEnter(GtkWidget* widget, GdkEventButton* event, pCanvas* p) -> int {
  Widget_mouseEnter(widget, event, p);
  return true;
}

static auto Label_mouseLeave(GtkWidget* widget, GdkEventButton* event, pCanvas* p) -> int {
  Widget_mouseLeave(widget, event, p);
  return true;
}

static auto Label_mousePress(GtkWidget* widget, GdkEventButton* event, pLabel* p) -> int {
  switch(event->button) {
  case 1: p->self().doMousePress(Mouse::Button::Left); break;
  case 2: p->self().doMousePress(Mouse::Button::Middle); break;
  case 3: p->self().doMousePress(Mouse::Button::Right); break;
  }
  return true;
}

static auto Label_mouseRelease(GtkWidget* widget, GdkEventButton* event, pLabel* p) -> int {
  switch(event->button) {
  case 1: p->self().doMouseRelease(Mouse::Button::Left); break;
  case 2: p->self().doMouseRelease(Mouse::Button::Middle); break;
  case 3: p->self().doMouseRelease(Mouse::Button::Right); break;
  }
  return true;
}

auto pLabel::construct() -> void {
  gtkWidget = gtk_event_box_new();
  subWidget = gtk_label_new("");
  gtk_widget_show(subWidget);
  gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget);

  setAlignment(state().alignment);
  setBackgroundColor(state().backgroundColor);
  setForegroundColor(state().foregroundColor);
  setText(state().text);

  g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Label_mousePress), (gpointer)this);
  g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Label_mouseRelease), (gpointer)this);
  #if HIRO_GTK==2
  g_signal_connect(G_OBJECT(subWidget), "expose-event", G_CALLBACK(Label_expose), (gpointer)this);
  #elif HIRO_GTK==3
  g_signal_connect(G_OBJECT(subWidget), "draw", G_CALLBACK(Label_draw), (gpointer)this);
  #endif
  g_signal_connect(G_OBJECT(gtkWidget), "enter-notify-event", G_CALLBACK(Label_mouseEnter), (gpointer)this);
  g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Label_mouseLeave), (gpointer)this);

  pWidget::construct();
}

auto pLabel::destruct() -> void {
  gtk_widget_destroy(subWidget);
  gtk_widget_destroy(gtkWidget);
}

auto pLabel::minimumSize() const -> Size {
  auto size = pFont::size(self().font(true), state().text);
  return {size.width(), size.height()};
}

auto pLabel::setAlignment(Alignment alignment) -> void {
  if(!alignment) alignment = {0.0, 0.5};
  gtk_misc_set_alignment(GTK_MISC(subWidget), alignment.horizontal(), alignment.vertical());
  auto justify = GTK_JUSTIFY_CENTER;
  if(alignment.horizontal() < 0.333) justify = GTK_JUSTIFY_LEFT;
  if(alignment.horizontal() > 0.666) justify = GTK_JUSTIFY_RIGHT;
  gtk_label_set_justify(GTK_LABEL(subWidget), justify);
}

auto pLabel::setBackgroundColor(Color color) -> void {
  //GTK3 will paint the wrong background color when a label is inside of a TabFrame
  //this is caused by the GtkEventBox wrapper that is required to paint custom backgrounds
  //handle background painting via "draw" or "expose-event" signals instead
}

auto pLabel::setForegroundColor(Color color) -> void {
  auto gdkColor = CreateColor(color);
  gtk_widget_modify_fg(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
}

auto pLabel::setText(const string& text) -> void {
  gtk_label_set_text(GTK_LABEL(subWidget), text);
}

auto pLabel::setVisible(bool visible) -> void {
  setBackgroundColor(state().backgroundColor);
  return pWidget::setVisible(visible);
}

}

#endif
