#include "osglobals_gtk.inl"
#include "oscontrol_gtk.inl"
#include "ospanel_gtk.inl"
#include "oswindow_gtk.inl"
#include "../osupdown.h"
#include "../osupdown.inl"
#include "../osgui.inl"
#include <core/event.h>
#include <core/heap.h>
#include <sewer/cassert.h>
#include <sewer/ptr.h>
#if !defined(__GTK3__)
#error This file is only for GTK Toolkit
#endif
typedef enum _udstate_t
{
ekNORMAL = 0,
ekUP_HOVER,
ekDOWN_HOVER,
ekUP_CLICK,
ekDOWN_CLICK
} udstate_t;
struct _osupdown_t
{
OSControl control;
udstate_t state;
Listener *OnClick;
};
static gboolean i_OnDraw(GtkWidget *widget, cairo_t *cr, OSUpDown *updown)
{
GtkStyleContext *ctx = _osglobals_button_context();
int w = gtk_widget_get_allocated_width(widget);
int h = gtk_widget_get_allocated_height(widget);
GtkStateFlags upstate = gtk_widget_get_state_flags(widget);
GtkStateFlags downstate = upstate;
int aw = w / 3;
int ax = (w - aw) / 2;
int ay = (h / 2 - aw) / 2;
cassert_no_null(updown);
switch (updown->state)
{
case ekUP_HOVER:
upstate = GTK_STATE_FLAG_PRELIGHT;
break;
case ekDOWN_HOVER:
downstate = GTK_STATE_FLAG_PRELIGHT;
break;
case ekUP_CLICK:
upstate = GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_ACTIVE;
break;
case ekDOWN_CLICK:
downstate = GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_ACTIVE;
break;
default:
break;
}
gtk_style_context_save(ctx);
gtk_style_context_set_state(ctx, upstate);
gtk_render_frame(ctx, cr, 0, 0, w, (h / 2) + 1);
gtk_style_context_set_state(ctx, downstate);
gtk_render_frame(ctx, cr, 0, (h / 2) + 1, w, (h / 2));
gtk_style_context_restore(ctx);
gtk_render_arrow(ctx, cr, 0, ax, ay, aw);
gtk_render_arrow(ctx, cr, G_PI, ax, (h / 2) + ay, aw);
return FALSE;
}
static void i_OnClick(OSUpDown *updown, const uint32_t index)
{
if (updown->OnClick != NULL)
{
EvButton params;
params.text = "";
params.state = ekGUI_ON;
params.index = index;
listener_event(updown->OnClick, ekGUI_EVENT_UPDOWN, updown, ¶ms, NULL, OSUpDown, EvButton, void);
}
}
static gboolean i_OnPress(GtkWidget *widget, GdkEventButton *event, OSUpDown *updown)
{
if (_oswindow_mouse_down(cast(updown, OSControl)) == TRUE)
{
int w = gtk_widget_get_allocated_height(widget);
int h = gtk_widget_get_allocated_height(widget);
cassert_no_null(updown);
if (event->x < 0 || event->x > w || event->y < 0 || event->y > h)
{
updown->state = ekNORMAL;
}
else if (event->y < h / 2)
{
if (event->type == GDK_BUTTON_RELEASE)
{
updown->state = ekUP_HOVER;
}
else
{
updown->state = ekUP_CLICK;
i_OnClick(updown, 0);
}
}
else
{
if (event->type == GDK_BUTTON_RELEASE)
{
updown->state = ekDOWN_HOVER;
}
else
{
updown->state = ekDOWN_CLICK;
i_OnClick(updown, 1);
}
}
gtk_widget_queue_draw(widget);
}
return TRUE;
}
static gboolean i_OnMove(GtkWidget *widget, GdkEventMotion *event, OSUpDown *updown)
{
int h = gtk_widget_get_allocated_height(widget);
cassert_no_null(updown);
if (event->y < h / 2)
updown->state = ekUP_HOVER;
else
updown->state = ekDOWN_HOVER;
gtk_widget_queue_draw(widget);
return TRUE;
}
static gboolean i_OnExit(GtkWidget *widget, GdkEventCrossing *event, OSUpDown *updown)
{
cassert_no_null(updown);
unref(event);
updown->state = ekNORMAL;
gtk_widget_queue_draw(widget);
return TRUE;
}
OSUpDown *osupdown_create(const uint32_t flags)
{
OSUpDown *updown = heap_new0(OSUpDown);
GtkWidget *widget = gtk_drawing_area_new();
unref(flags);
_oscontrol_init(&updown->control, ekGUI_TYPE_UPDOWN, widget, widget, TRUE);
gtk_widget_add_events(widget, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
g_signal_connect(widget, "motion-notify-event", G_CALLBACK(i_OnMove), (gpointer)updown);
g_signal_connect(widget, "leave-notify-event", G_CALLBACK(i_OnExit), (gpointer)updown);
g_signal_connect(widget, "button-press-event", G_CALLBACK(i_OnPress), (gpointer)updown);
g_signal_connect(widget, "button-release-event", G_CALLBACK(i_OnPress), (gpointer)updown);
g_signal_connect(widget, "draw", G_CALLBACK(i_OnDraw), (gpointer)updown);
return updown;
}
void osupdown_destroy(OSUpDown **updown)
{
cassert_no_null(updown);
cassert_no_null(*updown);
listener_destroy(&(*updown)->OnClick);
_oscontrol_destroy(*dcast(updown, OSControl));
heap_delete(updown, OSUpDown);
}
void osupdown_OnClick(OSUpDown *updown, Listener *listener)
{
cassert_no_null(updown);
listener_update(&updown->OnClick, listener);
}
void osupdown_tooltip(OSUpDown *updown, const char_t *text)
{
cassert_no_null(updown);
gtk_widget_set_tooltip_text(updown->control.widget, cast_const(text, gchar));
}
void osupdown_attach(OSUpDown *updown, OSPanel *panel)
{
_ospanel_attach_control(panel, cast(updown, OSControl));
}
void osupdown_detach(OSUpDown *updown, OSPanel *panel)
{
_ospanel_detach_control(panel, cast(updown, OSControl));
}
void osupdown_visible(OSUpDown *updown, const bool_t visible)
{
_oscontrol_set_visible(cast(updown, OSControl), visible);
}
void osupdown_enabled(OSUpDown *updown, const bool_t enabled)
{
_oscontrol_set_enabled(cast(updown, OSControl), enabled);
}
void osupdown_size(const OSUpDown *updown, real32_t *width, real32_t *height)
{
uint32_t eheight = _osglobals_entry_height();
cassert_no_null(width);
cassert_no_null(height);
if (eheight % 2 == 1)
eheight += 1;
*height = (real32_t)eheight;
if (eheight > 32)
*width = 32;
else
*width = *height;
unref(updown);
}
void osupdown_origin(const OSUpDown *updown, real32_t *x, real32_t *y)
{
_oscontrol_get_origin(cast_const(updown, OSControl), x, y);
}
void osupdown_frame(OSUpDown *updown, const real32_t x, const real32_t y, const real32_t width, const real32_t height)
{
_oscontrol_set_frame(cast(updown, OSControl), x, y, width, height);
}