void 
candidate_word_number_value_changed(GtkWidget* button, 
    gpointer user_data)
{
    FcitxWizardCandidateWidget *self = user_data;
    File_Conf_Data* config_conf = self->config_conf_data->conf_data;

    self->conf_data.candidate_word_number = 
        gtk_spin_button_get_value(GTK_SPIN_BUTTON(button));
    FcitxConfigBindValue(config_conf->config->config.configFile, "Output", 
        "CandidateWordNumber", 
        &self->conf_data.candidate_word_number, NULL, NULL);
}
void 
vertical_candidate_button_toggled(GtkWidget* button, 
    gpointer user_data)
{
    FcitxWizardCandidateWidget *self = user_data;
    File_Conf_Data* classic_ui_conf = self->classic_ui_conf_data->conf_data;

    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
        self->conf_data.vertical_candidate = true;
    else
        self->conf_data.vertical_candidate = false;

    FcitxConfigBindValue(classic_ui_conf->config->config.configFile, "ClassicUI", 
        "VerticalList", &self->conf_data.vertical_candidate, NULL, NULL);
}
void 
font_size_value_changed(GtkWidget* button, 
    gpointer user_data)
{
    FcitxWizardCandidateWidget *self = user_data;
    File_Conf_Data* classic_ui_conf = self->classic_ui_conf_data->conf_data;

    self->conf_data.font_size = 
        gtk_spin_button_get_value(GTK_SPIN_BUTTON(button));
    
    FcitxConfigBindValue(classic_ui_conf->config->config.configFile, "ClassicUI", 
        "FontSize", 
        &self->conf_data.font_size, NULL, NULL);

}
void 
font_button_font_set(GtkWidget* button, 
    gpointer user_data)
{
    const char *value;
    FcitxWizardCandidateWidget *self = user_data;
    File_Conf_Data* classic_ui_conf = self->classic_ui_conf_data->conf_data;

    value = gtk_font_button_get_font_name(GTK_FONT_BUTTON(self->font_button));

    if (self->conf_data.font == NULL &&
        (self->conf_data.font = malloc(FONT_VALUE_MAX_LEN)) == NULL)
    {
        FcitxLog(WARNING, _("Malloc memory(%d) failed.\n"), FONT_VALUE_MAX_LEN);
        return;
    }

    strcpy(self->conf_data.font, value);
    
    FcitxConfigBindValue(classic_ui_conf->config->config.configFile, "ClassicUI", 
        "Font", &self->conf_data.font, NULL, NULL);
}
static void
fcitx_config_widget_setup_ui(FcitxConfigWidget *self)
{
    FcitxConfigFileDesc* cfdesc = self->cfdesc;
    GtkWidget *cvbox = GTK_WIDGET(self);
    GtkWidget *configNotebook = gtk_notebook_new();
    gtk_box_pack_start(GTK_BOX(cvbox), configNotebook, TRUE, TRUE, 0);
    if (cfdesc) {
        bindtextdomain(cfdesc->domain, LOCALEDIR);
        bind_textdomain_codeset(cfdesc->domain, "UTF-8");

        FILE *fp;
        fp = FcitxXDGGetFileWithPrefix(self->prefix, self->name, "r", NULL);
        self->gconfig.configFile = FcitxConfigParseConfigFileFp(fp, cfdesc);

        FcitxConfigGroupDesc *cgdesc = NULL;
        FcitxConfigOptionDesc *codesc = NULL;
        for (cgdesc = cfdesc->groupsDesc;
                cgdesc != NULL;
                cgdesc = (FcitxConfigGroupDesc*)cgdesc->hh.next) {
            codesc = cgdesc->optionsDesc;
            if (codesc == NULL)
                continue;

            GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
            GtkWidget *table = gtk_table_new(2, HASH_COUNT(codesc), FALSE);
            GtkWidget *plabel = gtk_label_new(D_(cfdesc->domain, cgdesc->groupName));
            GtkWidget *scrollwnd = gtk_scrolled_window_new(NULL, NULL);

            gtk_container_set_border_width(GTK_CONTAINER(table), 0);
            gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
            gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwnd), table);
            gtk_box_pack_start(GTK_BOX(hbox), scrollwnd, TRUE, TRUE, 0);
            gtk_notebook_append_page(GTK_NOTEBOOK(configNotebook),
                                     hbox,
                                     plabel);

            int i = 0;
            for (; codesc != NULL;
                    codesc = (FcitxConfigOptionDesc*)codesc->hh.next, i++) {
                const char *s;
                if (codesc->desc && strlen(codesc->desc) != 0)
                    s = D_(cfdesc->domain, codesc->desc);
                else
                    s = D_(cfdesc->domain, codesc->optionName);

                GtkWidget *inputWidget = NULL;
                void *argument = NULL;

                switch (codesc->type) {
                case T_Integer:
                    inputWidget = gtk_spin_button_new_with_range(-1.0, 10000.0, 1.0);
                    argument = inputWidget;
                    break;
                case T_Color:
                    inputWidget = gtk_color_button_new();
                    argument = inputWidget;
                    break;
                case T_Boolean:
                    inputWidget = gtk_check_button_new();
                    argument = inputWidget;
                    break;
                case T_Font: {
                    inputWidget = gtk_hbox_new(FALSE, 0);
                    argument = gtk_font_button_new();
                    GtkWidget *button = gtk_button_new_with_label(_("Clear font setting"));
                    gtk_box_pack_start(GTK_BOX(inputWidget), argument, TRUE, TRUE, 0);
                    gtk_box_pack_start(GTK_BOX(inputWidget), button, FALSE, FALSE, 0);
                    gtk_font_button_set_use_size(GTK_FONT_BUTTON(argument), FALSE);
                    gtk_font_button_set_show_size(GTK_FONT_BUTTON(argument), FALSE);
                    g_signal_connect(G_OBJECT(button), "clicked", (GCallback) set_none_font_clicked, argument);
                }
                break;
                case T_Enum: {
                    int i;
                    FcitxConfigEnum *e = &codesc->configEnum;
#if GTK_CHECK_VERSION(2, 24, 0)
                    inputWidget = gtk_combo_box_text_new();
                    for (i = 0; i < e->enumCount; i ++) {
                        gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(inputWidget), D_(cfdesc->domain, e->enumDesc[i]));
                    }
#else
                    inputWidget = gtk_combo_box_new_text();
                    for (i = 0; i < e->enumCount; i ++)
                    {
                        gtk_combo_box_append_text(GTK_COMBO_BOX(inputWidget), D_(cfdesc->domain, e->enumDesc[i]));
                    }
#endif
                    argument = inputWidget;
                }
                break;
                case T_Hotkey: {
                    GtkWidget *button[2];
                    button[0] = keygrab_button_new();
                    button[1] = keygrab_button_new();
                    inputWidget = gtk_hbox_new(FALSE, 0);
                    gtk_box_pack_start(GTK_BOX(inputWidget), button[0], FALSE, TRUE, 0);
                    gtk_box_pack_start(GTK_BOX(inputWidget), button[1], FALSE, TRUE, 0);
                    argument = g_array_new(FALSE, FALSE, sizeof(void*));
                    g_array_append_val(argument, button[0]);
                    g_array_append_val(argument, button[1]);
                }
                break;
                case T_File:
                case T_Char:
                case T_String:
                    inputWidget = gtk_entry_new();
                    argument = inputWidget;
                    break;
                default:
                    break;
                }

                if (inputWidget) {
                    GtkWidget* label = gtk_label_new(s);
                    g_object_set(label, "xalign", 0.0f, NULL);
                    gtk_table_attach(GTK_TABLE(table), label, 0, 1, i, i + 1, GTK_FILL, GTK_SHRINK, 5, 5);
                    gtk_table_attach(GTK_TABLE(table), inputWidget, 1, 2, i, i + 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 4);
                    FcitxConfigBindValue(self->gconfig.configFile, cgdesc->groupName, codesc->optionName, NULL, sync_filter, argument);
                }
            }
        }

        FcitxConfigBindSync(&self->gconfig);
    }

    if (self->parser) {
        GHashTable* subconfigs = self->parser->subconfigs;
        if (g_hash_table_size(subconfigs) != 0) {
            GtkWidget *table = gtk_table_new(2, g_hash_table_size(subconfigs), FALSE);
            GtkWidget *plabel = gtk_label_new(_("Other"));
            GtkWidget *scrollwnd = gtk_scrolled_window_new(NULL, NULL);
            GtkWidget *viewport = gtk_viewport_new(NULL, NULL);

            gtk_container_set_border_width(GTK_CONTAINER(table), 4);
            gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
            gtk_container_add(GTK_CONTAINER(scrollwnd), viewport);
            gtk_container_add(GTK_CONTAINER(viewport), table);
            gtk_notebook_append_page(GTK_NOTEBOOK(configNotebook),
                                     scrollwnd,
                                     plabel);

            HashForeachContext context;
            context.i = 0;
            context.table = table;
            context.widget = self;
            g_hash_table_foreach(subconfigs, hash_foreach_cb, &context);
        }
    }

    gtk_widget_set_size_request(configNotebook, 500, -1);
    gtk_notebook_set_scrollable(GTK_NOTEBOOK(configNotebook), TRUE);
}