/*
 * This file is part of roccat-tools.
 *
 * roccat-tools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * roccat-tools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with roccat-tools. If not, see <http://www.gnu.org/licenses/>.
 */

#include <gaminggear/gaminggear_macro_dialog.h>
#include <gaminggear/key_translations.h>
#include <gaminggear/gdk_key_translations.h>
#include <gaminggear/hid_uid.h>
#include "ryosconfig_key_combo_box.h"
#include "roccat_talk_target_dialog.h"
#include "roccat_shortcut_dialog.h"
#include "roccat_timer_dialog.h"
#include "roccat_key_dialog.h"
#include "roccat_warning_dialog.h"
#include "roccat_talk.h"
#include "roccat_helper.h"
#include "gtk_roccat_helper.h"
#include "g_cclosure_roccat_marshaller.h"

#define RYOSCONFIG_KEY_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), RYOSCONFIG_KEY_COMBO_BOX_TYPE, RyosconfigKeyComboBoxClass))
#define IS_RYOSCONFIG_KEY_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RYOSCONFIG_KEY_COMBO_BOX_TYPE))
#define RYOSCONFIG_KEY_COMBO_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RYOSCONFIG_KEY_COMBO_BOX_TYPE, RyosconfigKeyComboBoxClass))
#define RYOSCONFIG_KEY_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), RYOSCONFIG_KEY_COMBO_BOX_TYPE, RyosconfigKeyComboBoxPrivate))

typedef struct _RyosconfigKeyComboBoxClass RyosconfigKeyComboBoxClass;
typedef struct _RyosconfigKeyComboBoxPrivate RyosconfigKeyComboBoxPrivate;

struct _RyosconfigKeyComboBox {
	RoccatKeyComboBox parent;
	RyosconfigKeyComboBoxPrivate *priv;
};

struct _RyosconfigKeyComboBoxClass {
	RoccatKeyComboBoxClass parent_class;
	GtkTreeModel *model;
};

struct _RyosconfigKeyComboBoxPrivate {
	RyosconfigKeyComboBoxData *data;
	guint standard;
	gulong changed_handler_id;
};

G_DEFINE_TYPE(RyosconfigKeyComboBox, ryosconfig_key_combo_box, ROCCAT_KEY_COMBO_BOX_TYPE);

typedef enum {
	RYOSCONFIG_KEY_COMBO_BOX_TYPE_STANDARD = 0xe000,
	RYOSCONFIG_KEY_COMBO_BOX_TYPE_REMAP,
} RyosconfigKeyComboBoxType;

enum {
	KEY_CHANGED,
	REMAP,
	LAST_SIGNAL,
};

static guint signals[LAST_SIGNAL] = { 0 };

static gchar *shortcut_name(RyosKey const *key) {
	return roccat_shortcut_dialog_create_name(roccat_get_bit(key->modifier, RYOS_KEY_MODIFIER_BIT_CTRL),
			roccat_get_bit(key->modifier, RYOS_KEY_MODIFIER_BIT_SHIFT),
			roccat_get_bit(key->modifier, RYOS_KEY_MODIFIER_BIT_ALT),
			roccat_get_bit(key->modifier, RYOS_KEY_MODIFIER_BIT_WIN),
			key->key);
}

gchar *ryosconfig_key_combo_box_get_text_for_data(RyosconfigKeyComboBox *key_combo_box, RyosconfigKeyComboBoxData const *data) {
	gchar *text;
	gchar *temp;
	guint type;

	type = data->key.type;

	switch (type) {
	case RYOS_KEY_TYPE_TALK_EASYSHIFT:
	case RYOS_KEY_TYPE_TALK_EASYSHIFT_LOCK:
	case RYOS_KEY_TYPE_TALK_EASYAIM_1:
	case RYOS_KEY_TYPE_TALK_EASYAIM_2:
	case RYOS_KEY_TYPE_TALK_EASYAIM_3:
	case RYOS_KEY_TYPE_TALK_EASYAIM_4:
	case RYOS_KEY_TYPE_TALK_EASYAIM_5:
		text = g_strdup(ryos_rkp_talk_get_name(&data->talk));
		break;
	case RYOS_KEY_TYPE_LIGHT:
		text = g_strdup("Light");
		break;
	case RYOS_KEY_TYPE_RECORD:
		text = g_strdup("Live record");
		break;
	case RYOS_KEY_TYPE_STANDARD_SHIFT_1:
		text = g_strdup("Shift+1");
		break;
	case RYOS_KEY_TYPE_STANDARD_SHIFT_2:
		text = g_strdup("Shift+2");
		break;
	case RYOS_KEY_TYPE_STANDARD_SHIFT_3:
		text = g_strdup("Shift+3");
		break;
	case RYOS_KEY_TYPE_STANDARD_SHIFT_4:
		text = g_strdup("Shift+4");
		break;
	case RYOS_KEY_TYPE_STANDARD_SHIFT_5:
		text = g_strdup("Shift+5");
		break;
	case RYOS_KEY_TYPE_STANDARD_CTRL_1:
		text = g_strdup("Ctrl+1");
		break;
	case RYOS_KEY_TYPE_STANDARD_CTRL_2:
		text = g_strdup("Ctrl+2");
		break;
	case RYOS_KEY_TYPE_STANDARD_CTRL_3:
		text = g_strdup("Ctrl+3");
		break;
	case RYOS_KEY_TYPE_STANDARD_CTRL_4:
		text = g_strdup("Ctrl+4");
		break;
	case RYOS_KEY_TYPE_STANDARD_CTRL_5:
		text = g_strdup("Ctrl+5");
		break;
	case RYOS_KEY_TYPE_SHORTCUT:
		temp = shortcut_name(&data->key);
		text = g_strdup_printf("Shortcut: %s", temp);
		g_free(temp);
		break;
	case RYOS_KEY_TYPE_MACRO:
		text = g_strdup_printf("Macro: %s/%s", data->macro.macroset_name, data->macro.macro_name);
		break;
	case RYOS_KEY_TYPE_QUICKLAUNCH:
		temp = ryos_rkp_quicklaunch_get_name(&data->quicklaunch);
		text = g_strdup_printf("Quicklaunch: %s", temp);
		g_free(temp);
		break;
	case RYOS_KEY_TYPE_TIMER:
		text = g_strdup_printf("Timer: %s", (gchar const *)data->timer.name);
		break;
	default:
		text = roccat_key_combo_box_model_get_title_for_type_explicit(gtk_combo_box_get_model(GTK_COMBO_BOX(key_combo_box)), type);
		if (!text)
			text = gaminggear_hid_to_keyname(type);
		break;
	}

	return text;
}

void ryosconfig_key_combo_box_update(RyosconfigKeyComboBox *key_combo_box) {
	RyosconfigKeyComboBoxPrivate *priv = key_combo_box->priv;
	gchar *text;

	text = ryosconfig_key_combo_box_get_text_for_data(key_combo_box, priv->data);

	g_signal_handler_block(G_OBJECT(key_combo_box), priv->changed_handler_id);
	roccat_key_combo_box_set_text(ROCCAT_KEY_COMBO_BOX(key_combo_box), text);
	g_signal_handler_unblock(G_OBJECT(key_combo_box), priv->changed_handler_id);

	g_free(text);
}

static gboolean key_quicklaunch(RyosconfigKeyComboBox *key_combo_box) {
	RyosconfigKeyComboBoxPrivate *priv = key_combo_box->priv;
	GtkWidget *dialog;
	gboolean retval = FALSE;
	gchar *path;

	dialog = gtk_file_chooser_dialog_new("Select executable",
			gtk_roccat_widget_get_gtk_window(GTK_WIDGET(key_combo_box)),
			GTK_FILE_CHOOSER_ACTION_OPEN,
			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
			GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
			NULL);

	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
		ryos_key_set_to_normal(&priv->data->key, RYOS_KEY_TYPE_QUICKLAUNCH);
		path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
		ryos_rkp_quicklaunch_set(&priv->data->quicklaunch, path);
		g_free(path);
		retval = TRUE;
	}
	gtk_widget_destroy(dialog);
	return retval;
}

static gboolean key_macro(RyosconfigKeyComboBox *key_combo_box) {
	RyosconfigKeyComboBoxPrivate *priv = key_combo_box->priv;
	GtkWindow *parent;
	GaminggearMacro *gaminggear_macro;
	RyosMacro *ryos_macro;
	gboolean result;
	GError *local_error = NULL;

	parent = gtk_roccat_widget_get_gtk_window(GTK_WIDGET(key_combo_box));
	gaminggear_macro = gaminggear_macro_dialog(parent);
	if (!gaminggear_macro)
		return FALSE;

	ryos_macro = (RyosMacro *)g_malloc0(sizeof(RyosMacro));
	result = gaminggear_macro_to_ryos_macro(gaminggear_macro, ryos_macro, &local_error);
	gaminggear_macro_free(gaminggear_macro);
	if (!result) {
		roccat_handle_error_dialog(parent, "Can't convert macro", &local_error);
		g_free(ryos_macro);
		return FALSE;
	}

	ryos_macro_copy(&priv->data->macro, ryos_macro);
	g_free(ryos_macro);
	ryos_key_set_to_normal(&priv->data->key, RYOS_KEY_TYPE_MACRO);

	return TRUE;
}

static gboolean key_shortcut(RyosconfigKeyComboBox *key_combo_box) {
	RyosconfigKeyComboBoxPrivate *priv = key_combo_box->priv;
	RoccatShortcutDialog *dialog;
	gboolean retval = FALSE;

	dialog = ROCCAT_SHORTCUT_DIALOG(roccat_shortcut_dialog_new(gtk_roccat_widget_get_gtk_window(GTK_WIDGET(key_combo_box))));
	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
		ryos_key_set_to_shortcut(&priv->data->key,
				gaminggear_xkeycode_to_hid(roccat_shortcut_dialog_get_xkeycode(dialog)),
				ryos_key_build_shortcut_modifier(
						roccat_shortcut_dialog_get_ctrl(dialog),
						roccat_shortcut_dialog_get_shift(dialog),
						roccat_shortcut_dialog_get_alt(dialog),
						roccat_shortcut_dialog_get_win(dialog)));
		retval = TRUE;
	}
	gtk_widget_destroy(GTK_WIDGET(dialog));
	return retval;
}

static gboolean key_timer(RyosconfigKeyComboBox *key_combo_box) {
	RyosconfigKeyComboBoxPrivate *priv = key_combo_box->priv;
	RoccatTimer *roccat_timer;
	gboolean retval = FALSE;

	roccat_timer = roccat_timer_dialog(gtk_roccat_widget_get_gtk_window(GTK_WIDGET(key_combo_box)));
	if (roccat_timer) {
		ryos_key_set_to_normal(&priv->data->key, RYOS_KEY_TYPE_TIMER);
		roccat_timer_to_ryos_rkp_timer(roccat_timer, &priv->data->timer);
		g_free(roccat_timer);
		retval = TRUE;
	}
	return retval;
}

static gboolean key_normal(RyosconfigKeyComboBox *key_combo_box, guint type) {
	gboolean retval = TRUE;

	if (key_combo_box->priv->data->key.type == type)
		retval = FALSE;

	ryos_key_set_to_normal(&key_combo_box->priv->data->key, type);

	return retval;
}

static void key_remap(RyosconfigKeyComboBox *key_combo_box) {
	RyosconfigKeyComboBoxPrivate *priv = key_combo_box->priv;
	RoccatKeyDialog *dialog;
	guint8 old_hid;
	guint8 new_hid;

	dialog = ROCCAT_KEY_DIALOG(roccat_key_dialog_new(gtk_roccat_widget_get_gtk_window(GTK_WIDGET(key_combo_box))));
	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
		old_hid = priv->data->key.type;
		new_hid = gaminggear_xkeycode_to_hid(roccat_key_dialog_get_xkeycode(dialog));

		if (old_hid != new_hid)
			g_signal_emit((gpointer)key_combo_box, signals[REMAP], 0, old_hid, new_hid);

	}
	gtk_widget_destroy(GTK_WIDGET(dialog));
}

static gboolean key_talk(RyosconfigKeyComboBox *key_combo_box, guint type) {
	RyosconfigKeyComboBoxData *data = key_combo_box->priv->data;
	RoccatTalkTargetDialog *talk_target_dialog;
	guint target;
	gboolean retval = FALSE;
	gchar *text;

	talk_target_dialog = ROCCAT_TALK_TARGET_DIALOG(roccat_talk_target_dialog_new(
			gtk_roccat_widget_get_gtk_window(GTK_WIDGET(key_combo_box)), ROCCAT_TALK_DEVICE_KEYBOARD));
	if (gtk_dialog_run(GTK_DIALOG(talk_target_dialog)) == GTK_RESPONSE_ACCEPT) {
		target = roccat_talk_target_dialog_get_value(talk_target_dialog);

		switch (type) {
		case RYOS_KEY_TYPE_TALK_EASYSHIFT:
			text = g_strdup_printf("Easyshift: %s", roccat_talk_device_get_text_static(target));
			break;
		case RYOS_KEY_TYPE_TALK_EASYSHIFT_LOCK:
			text = g_strdup_printf("Easyshift Lock: %s", roccat_talk_device_get_text_static(target));
			break;
		case RYOS_KEY_TYPE_TALK_EASYAIM_1:
			text = g_strdup_printf("Easyaim 1: %s", roccat_talk_device_get_text_static(target));
			break;
		case RYOS_KEY_TYPE_TALK_EASYAIM_2:
			text = g_strdup_printf("Easyaim 2: %s", roccat_talk_device_get_text_static(target));
			break;
		case RYOS_KEY_TYPE_TALK_EASYAIM_3:
			text = g_strdup_printf("Easyaim 3: %s", roccat_talk_device_get_text_static(target));
			break;
		case RYOS_KEY_TYPE_TALK_EASYAIM_4:
			text = g_strdup_printf("Easyaim 4: %s", roccat_talk_device_get_text_static(target));
			break;
		case RYOS_KEY_TYPE_TALK_EASYAIM_5:
			text = g_strdup_printf("Easyaim 5: %s", roccat_talk_device_get_text_static(target));
			break;
		default:
			text = g_strdup_printf("unknown talk type %u", type);
			break;
		}

		ryos_key_set_to_normal(&data->key, type);
		ryos_rkp_talk_set(&data->talk, target, type, text);
		retval = TRUE;
	}

	gtk_widget_destroy(GTK_WIDGET(talk_target_dialog));
	return retval;
}

static void changed_cb(GtkComboBox *combo, gpointer user_data) {
	RyosconfigKeyComboBox *key_combo_box = RYOSCONFIG_KEY_COMBO_BOX(combo);
	RyosconfigKeyComboBoxPrivate *priv = key_combo_box->priv;
	guint type;
	gboolean changed;

	type = roccat_key_combo_box_get_active_type(ROCCAT_KEY_COMBO_BOX(combo));
	if (type == ROCCAT_KEY_COMBO_BOX_TYPE_NONE)
		return;

	if (type == RYOSCONFIG_KEY_COMBO_BOX_TYPE_STANDARD)
		type = priv->standard;

	switch (type) {
	case RYOSCONFIG_KEY_COMBO_BOX_TYPE_REMAP:
		key_remap(key_combo_box);
		return;
		break;
	case RYOS_KEY_TYPE_MACRO:
		changed = key_macro(key_combo_box);
		break;
	case RYOS_KEY_TYPE_SHORTCUT:
		changed = key_shortcut(key_combo_box);
		break;
	case RYOS_KEY_TYPE_QUICKLAUNCH:
		changed = key_quicklaunch(key_combo_box);
		break;
	case RYOS_KEY_TYPE_TIMER:
		changed = key_timer(key_combo_box);
		break;
	case RYOS_KEY_TYPE_TALK_EASYSHIFT:
	case RYOS_KEY_TYPE_TALK_EASYSHIFT_LOCK:
	case RYOS_KEY_TYPE_TALK_EASYAIM_1:
	case RYOS_KEY_TYPE_TALK_EASYAIM_2:
	case RYOS_KEY_TYPE_TALK_EASYAIM_3:
	case RYOS_KEY_TYPE_TALK_EASYAIM_4:
	case RYOS_KEY_TYPE_TALK_EASYAIM_5:
		changed = key_talk(key_combo_box, type);
		break;
	default:
		changed = key_normal(key_combo_box, type);
	}

	ryosconfig_key_combo_box_update(key_combo_box);
	if (changed)
		g_signal_emit((gpointer)key_combo_box, signals[KEY_CHANGED], 0);
}

void ryosconfig_key_combo_box_set_data_pointer(RyosconfigKeyComboBox *key_combo_box, RyosconfigKeyComboBoxData *data) {
	key_combo_box->priv->data = data;
	ryosconfig_key_combo_box_update(key_combo_box);
}

RyosconfigKeyComboBoxData *ryosconfig_key_combo_box_get_data_pointer(RyosconfigKeyComboBox *key_combo_box) {
	return key_combo_box->priv->data;
}

void ryosconfig_key_combo_box_set_standard(RyosconfigKeyComboBox *key_combo_box, guint standard) {
	key_combo_box->priv->standard = standard;
}

GtkWidget *ryosconfig_key_combo_box_new(guint mask, guint standard) {
	RyosconfigKeyComboBox *key_combo_box;
	RyosconfigKeyComboBoxClass *key_combo_box_class;
	RyosconfigKeyComboBoxPrivate *priv;

	key_combo_box = RYOSCONFIG_KEY_COMBO_BOX(g_object_new(RYOSCONFIG_KEY_COMBO_BOX_TYPE,
			"exclude-mask", mask,
			NULL));

	priv = key_combo_box->priv;

	ryosconfig_key_combo_box_set_standard(key_combo_box, standard);

	key_combo_box_class = RYOSCONFIG_KEY_COMBO_BOX_GET_CLASS(key_combo_box);
	roccat_key_combo_box_set_model(ROCCAT_KEY_COMBO_BOX(key_combo_box), key_combo_box_class->model);

	priv->changed_handler_id = g_signal_connect(G_OBJECT(key_combo_box), "changed", G_CALLBACK(changed_cb), NULL);

	return GTK_WIDGET(key_combo_box);
}

static void ryosconfig_key_combo_box_init(RyosconfigKeyComboBox *key_combo_box) {
	RyosconfigKeyComboBoxPrivate *priv = RYOSCONFIG_KEY_COMBO_BOX_GET_PRIVATE(key_combo_box);
	key_combo_box->priv = priv;
}

static GtkTreeModel *button_info_model_new(void) {
	GtkTreeStore *store;
	GtkTreeIter iter;
	GtkTreeIter toplevel;

	store = roccat_key_combo_box_store_new();

	roccat_key_combo_box_store_append(store, &toplevel, NULL, "Apps", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);

	roccat_key_combo_box_store_append(store, NULL, &toplevel, "EMail", RYOS_KEY_TYPE_APP_EMAIL, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Calculator", RYOS_KEY_TYPE_APP_CALCULATOR, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "My Computer", RYOS_KEY_TYPE_APP_MY_COMPUTER, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Browser", RYOS_KEY_TYPE_APP_BROWSER, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);

	roccat_key_combo_box_store_append(store, &toplevel, NULL, "Easyshift", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);

	roccat_key_combo_box_store_append(store, &iter, &toplevel, "Self", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Self Easyshift", RYOS_KEY_TYPE_EASYSHIFT, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);

	roccat_key_combo_box_store_append(store, &iter, &toplevel, "Other", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Other Easyshift", RYOS_KEY_TYPE_TALK_EASYSHIFT, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Other Easyshift lock", RYOS_KEY_TYPE_TALK_EASYSHIFT_LOCK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Other Easyaim Setting 1", RYOS_KEY_TYPE_TALK_EASYAIM_1, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Other Easyaim Setting 2", RYOS_KEY_TYPE_TALK_EASYAIM_2, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Other Easyaim Setting 3", RYOS_KEY_TYPE_TALK_EASYAIM_3, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Other Easyaim Setting 4", RYOS_KEY_TYPE_TALK_EASYAIM_4, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Other Easyaim Setting 5", RYOS_KEY_TYPE_TALK_EASYAIM_5, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);

	roccat_key_combo_box_store_append(store, &iter, &toplevel, "Both", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);
	roccat_key_combo_box_store_append(store, NULL, &iter, "Both Easyshift", RYOS_KEY_TYPE_TALK_EASYSHIFT_ALL, RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK);

	roccat_key_combo_box_store_append(store, &toplevel, NULL, "Multimedia", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);

	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Open player", RYOS_KEY_TYPE_MULTIMEDIA_OPEN_PLAYER, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Previous track", RYOS_KEY_TYPE_MULTIMEDIA_PREV_TRACK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Next track", RYOS_KEY_TYPE_MULTIMEDIA_NEXT_TRACK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Play/Pause", RYOS_KEY_TYPE_MULTIMEDIA_PLAY_PAUSE, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Stop", RYOS_KEY_TYPE_MULTIMEDIA_STOP, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Mute", RYOS_KEY_TYPE_MULTIMEDIA_MUTE, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Volume up", RYOS_KEY_TYPE_MULTIMEDIA_VOLUME_UP, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Volume down", RYOS_KEY_TYPE_MULTIMEDIA_VOLUME_DOWN, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);

	roccat_key_combo_box_store_append(store, &toplevel, NULL, "Profile", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);

	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile up", RYOS_KEY_TYPE_PROFILE_UP, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile down", RYOS_KEY_TYPE_PROFILE_DOWN, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile cycle", RYOS_KEY_TYPE_PROFILE_CYCLE, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile 1", RYOS_KEY_TYPE_PROFILE_1, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile 2", RYOS_KEY_TYPE_PROFILE_2, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile 3", RYOS_KEY_TYPE_PROFILE_3, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile 4", RYOS_KEY_TYPE_PROFILE_4, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Profile 5", RYOS_KEY_TYPE_PROFILE_5, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);

	roccat_key_combo_box_store_append(store, &toplevel, NULL, "Timer", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);

	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Timer start", RYOS_KEY_TYPE_TIMER, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Timer stop", RYOS_KEY_TYPE_TIMER_STOP, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);

	roccat_key_combo_box_store_append(store, &toplevel, NULL, "WWW", ROCCAT_KEY_COMBO_BOX_TYPE_NONE, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);

	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Search", RYOS_KEY_TYPE_WWW_SEARCH, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Home", RYOS_KEY_TYPE_WWW_HOME, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Back", RYOS_KEY_TYPE_WWW_BACK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Forward", RYOS_KEY_TYPE_WWW_FORWARD, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Stop", RYOS_KEY_TYPE_WWW_STOP, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Refresh", RYOS_KEY_TYPE_WWW_REFRESH, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, &toplevel, "Favorites", RYOS_KEY_TYPE_WWW_FAVORITES, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);

	roccat_key_combo_box_store_append(store, NULL, NULL, "Shortcut", RYOS_KEY_TYPE_SHORTCUT, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, NULL, "Macro", RYOS_KEY_TYPE_MACRO, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED);
	roccat_key_combo_box_store_append(store, NULL, NULL, "Macro play/pause", RYOS_KEY_TYPE_MACRO_PLAY_PAUSE, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, NULL, "Open driver", RYOS_KEY_TYPE_OPEN_DRIVER, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY);
	roccat_key_combo_box_store_append(store, NULL, NULL, "Quicklaunch", RYOS_KEY_TYPE_QUICKLAUNCH, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED);

	roccat_key_combo_box_store_append(store, NULL, NULL, "Standard", RYOSCONFIG_KEY_COMBO_BOX_TYPE_STANDARD, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);
	roccat_key_combo_box_store_append(store, NULL, NULL, "Remap", RYOSCONFIG_KEY_COMBO_BOX_TYPE_REMAP, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY);
	roccat_key_combo_box_store_append(store, NULL, NULL, "Disabled", RYOS_KEY_TYPE_DISABLED, ROCCAT_KEY_COMBO_BOX_GROUP_NONE);

	return GTK_TREE_MODEL(store);
}

static void ryosconfig_key_combo_box_class_init(RyosconfigKeyComboBoxClass *klass) {
	g_type_class_add_private(klass, sizeof(RyosconfigKeyComboBoxPrivate));
	klass->model = button_info_model_new();

	signals[KEY_CHANGED] = g_signal_new("key-changed",
			G_TYPE_FROM_CLASS(klass),
			G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);

	signals[REMAP] = g_signal_new("remap",
			G_TYPE_FROM_CLASS(klass),
			G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			0, NULL, NULL, g_cclosure_roccat_marshal_VOID__UINT_UINT, G_TYPE_NONE,
			2, G_TYPE_UINT, G_TYPE_UINT);
}
