/* * Copyright (C) 2007-2009 Gabest * http://www.gabest.org * * This Program 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, or (at your option) * any later version. * * This Program 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 GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. * http://www.gnu.org/copyleft/gpl.html * */ #include "stdafx.h" #include #include "GS.h" #include "GSdx.h" #include "GSdxResources.h" #include "GSSetting.h" // Port of deprecated GTK2 API to recent GTK3. Those defines // could prove handy for testing #define GTK3_MONITOR_API GTK_CHECK_VERSION(3, 22, 0) #define GTK3_GRID_API GTK_CHECK_VERSION(3, 12, 0) static GtkWidget* s_hack_frame; bool BigEnough() { #if GTK3_MONITOR_API GdkDisplay* display = gdk_display_get_default(); GdkSeat* seat = gdk_display_get_default_seat(display); GdkDevice* pointer = gdk_seat_get_pointer(seat); int x; int y; gdk_device_get_position(pointer, nullptr, &x, &y); GdkMonitor* monitor = gdk_display_get_monitor_at_point(display, x, y); GdkRectangle my_geometry{}; gdk_monitor_get_geometry(monitor, &my_geometry); return my_geometry.height > 1000; #else return (gdk_screen_get_height(gdk_screen_get_default()) > 1000); #endif } void AddTooltip(GtkWidget* w, int idc) { gtk_widget_set_tooltip_text(w, dialog_message(idc)); } void AddTooltip(GtkWidget* w1, GtkWidget* w2, int idc) { AddTooltip(w1, idc); AddTooltip(w2, idc); } GtkWidget* CreateVbox() { #if GTK_CHECK_VERSION(3, 0, 0) return gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); #else return gtk_vbox_new(false, 5); #endif } GtkWidget* left_label(const char* lbl) { GtkWidget* w = gtk_label_new(lbl); #if GTK_CHECK_VERSION(3, 0, 0) gtk_widget_set_halign(w, GTK_ALIGN_START); #else gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5); #endif return w; } void CB_ChangedComboBox(GtkComboBox* combo, gpointer user_data) { int p = gtk_combo_box_get_active(combo); auto s = reinterpret_cast*>(g_object_get_data(G_OBJECT(combo), "Settings")); try { theApp.SetConfig((char*)user_data, s->at(p).value); } catch (...) { } } GtkWidget* CreateComboBoxFromVector(const std::vector& s, const char* opt_name) { GtkWidget* combo_box = gtk_combo_box_text_new(); int32_t opt_value = theApp.GetConfigI(opt_name); int opt_position = 0; for (size_t i = 0; i < s.size(); i++) { std::string label = s[i].name; if (!s[i].note.empty()) label += format(" (%s)", s[i].note.c_str()); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), label.c_str()); if (s[i].value == opt_value) opt_position = i; } gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), opt_position); g_signal_connect(combo_box, "changed", G_CALLBACK(CB_ChangedComboBox), const_cast(opt_name)); g_object_set_data(G_OBJECT(combo_box), "Settings", (void*)&s); return combo_box; } void CB_EntryActived(GtkEntry* entry, gpointer user_data) { int hex_value = 0; const gchar* data = gtk_entry_get_text(entry); if (sscanf(data, "%X", &hex_value) == 1) theApp.SetConfig((char*)user_data, hex_value); } GtkWidget* CreateTextBox(const char* opt_name) { GtkWidget* entry = gtk_entry_new(); int hex_value = theApp.GetConfigI(opt_name); gchar* data = (gchar*)g_malloc(sizeof(gchar) * 40); sprintf(data, "%X", hex_value); gtk_entry_set_text(GTK_ENTRY(entry), data); g_free(data); g_signal_connect(entry, "activate", G_CALLBACK(CB_EntryActived), const_cast(opt_name)); g_signal_connect(entry, "changed", G_CALLBACK(CB_EntryActived), const_cast(opt_name)); return entry; } void CB_ToggleCheckBox(GtkToggleButton* togglebutton, gpointer user_data) { char* opt = (char*)user_data; theApp.SetConfig(opt, (int)gtk_toggle_button_get_active(togglebutton)); if (strcmp(opt, "UserHacks") == 0) { gtk_widget_set_sensitive(s_hack_frame, gtk_toggle_button_get_active(togglebutton)); } } GtkWidget* CreateCheckBox(const char* label, const char* opt_name) { GtkWidget* check = gtk_check_button_new_with_label(label); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), theApp.GetConfigB(opt_name)); g_signal_connect(check, "toggled", G_CALLBACK(CB_ToggleCheckBox), const_cast(opt_name)); return check; } void CB_SpinButton(GtkSpinButton* spin, gpointer user_data) { theApp.SetConfig((char*)user_data, (int)gtk_spin_button_get_value(spin)); } GtkWidget* CreateSpinButton(double min, double max, const char* opt_name) { GtkWidget* spin = gtk_spin_button_new_with_range(min, max, 1); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), theApp.GetConfigI(opt_name)); g_signal_connect(spin, "value-changed", G_CALLBACK(CB_SpinButton), const_cast(opt_name)); return spin; } void CB_RangeChanged(GtkRange* range, gpointer user_data) { theApp.SetConfig((char*)user_data, (int)gtk_range_get_value(range)); } GtkWidget* CreateScale(const char* opt_name, int scale_min = 0, int scale_max = 100, int scale_range = 10) { #if GTK_CHECK_VERSION(3, 0, 0) GtkWidget* scale = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, scale_min, scale_max, scale_range); #else GtkWidget* scale = gtk_hscale_new_with_range(scale_min, scale_max, scale_range); #endif gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT); gtk_range_set_value(GTK_RANGE(scale), theApp.GetConfigI(opt_name)); g_signal_connect(scale, "value-changed", G_CALLBACK(CB_RangeChanged), const_cast(opt_name)); return scale; } void CB_PickFile(GtkFileChooserButton* chooser, gpointer user_data) { theApp.SetConfig((char*)user_data, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser))); } GtkWidget* CreateFileChooser(GtkFileChooserAction action, const char* label, const char* opt_name) { GtkWidget* chooser = gtk_file_chooser_button_new(label, action); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), theApp.GetConfigS(opt_name).c_str()); g_signal_connect(chooser, "file-set", G_CALLBACK(CB_PickFile), const_cast(opt_name)); return chooser; } static int s_table_line = 0; void AttachInTable(GtkWidget* table, GtkWidget* w, int pos, int pad = 0, int size = 1) { #if GTK3_GRID_API gtk_widget_set_margin_start(w, pad); gtk_widget_set_hexpand(w, false); gtk_grid_attach(GTK_GRID(table), w, pos, s_table_line, size, 1); #else GtkAttachOptions opt = (GtkAttachOptions)(/*GTK_EXPAND | */ GTK_FILL); // default gtk_table_attach(GTK_TABLE(table), w, pos, pos + size, s_table_line, s_table_line + 1, opt, opt, pad, 0); #endif } void InsertWidgetInTable(GtkWidget* table, GtkWidget* left, GtkWidget* right = NULL, GtkWidget* third = NULL) { guint l_xpad = GTK_IS_CHECK_BUTTON(left) ? 0 : 22; if (!left) { AttachInTable(table, right, 1); } else if (!right) { AttachInTable(table, left, 0, l_xpad); } else if (right == left) { AttachInTable(table, right, 0, 0, 2); } else { AttachInTable(table, left, 0, l_xpad); AttachInTable(table, right, 1); } if (third) { AttachInTable(table, third, 2); } s_table_line++; } GtkWidget* CreateTableInBox(GtkWidget* parent_box, const char* frame_title, int row, int col) { #if GTK3_GRID_API GtkWidget* table = gtk_grid_new(); gtk_widget_set_hexpand(table, true); #else GtkWidget* table = gtk_table_new(row, col, false); #endif GtkWidget* container = (frame_title) ? gtk_frame_new(frame_title) : CreateVbox(); gtk_container_add(GTK_CONTAINER(container), table); gtk_container_add(GTK_CONTAINER(parent_box), container); return table; } void populate_hw_table(GtkWidget* hw_table) { GtkWidget* hack_enable_check = CreateCheckBox("Enable User Hacks", "UserHacks"); GtkWidget* acc_date_check = CreateCheckBox("Accurate DATE", "accurate_date"); GtkWidget* paltex_check = CreateCheckBox("Allow 8 bits textures", "paltex"); GtkWidget* large_fb_check = CreateCheckBox("Large Framebuffer", "large_framebuffer"); GtkWidget* fsaa_label = left_label("Internal Resolution:"); GtkWidget* fsaa_combo_box = CreateComboBoxFromVector(theApp.m_gs_upscale_multiplier, "upscale_multiplier"); GtkWidget* af_label = left_label("Anisotropic Filtering:"); GtkWidget* af_combo_box = CreateComboBoxFromVector(theApp.m_gs_max_anisotropy, "MaxAnisotropy"); GtkWidget* dither_label = left_label("Dithering (PgDn):"); GtkWidget* dither_combo_box = CreateComboBoxFromVector(theApp.m_gs_dithering, "dithering_ps2"); GtkWidget* mipmap_label = left_label("Mipmapping (Insert):"); GtkWidget* mipmap_combo_box = CreateComboBoxFromVector(theApp.m_gs_hw_mipmapping, "mipmap_hw"); GtkWidget* crc_label = left_label("CRC Hack Level:"); GtkWidget* crc_combo_box = CreateComboBoxFromVector(theApp.m_gs_crc_level, "crc_hack_level"); GtkWidget* acc_bld_label = left_label("Blending Accuracy:"); GtkWidget* acc_bld_combo_box = CreateComboBoxFromVector(theApp.m_gs_acc_blend_level, "accurate_blending_unit"); // Some helper string gtk_widget_set_tooltip_text(hack_enable_check, "Enable the HW hack option panel"); AddTooltip(acc_date_check, IDC_ACCURATE_DATE); AddTooltip(paltex_check, IDC_PALTEX); AddTooltip(large_fb_check, IDC_LARGE_FB); AddTooltip(crc_label, crc_combo_box, IDC_CRC_LEVEL); AddTooltip(af_label, af_combo_box, IDC_AFCOMBO); AddTooltip(mipmap_label, IDC_MIPMAP_HW); AddTooltip(mipmap_combo_box, IDC_MIPMAP_HW); AddTooltip(acc_bld_label, acc_bld_combo_box, IDC_ACCURATE_BLEND_UNIT); s_table_line = 0; InsertWidgetInTable(hw_table, hack_enable_check, acc_date_check); InsertWidgetInTable(hw_table, paltex_check, large_fb_check); InsertWidgetInTable(hw_table, fsaa_label, fsaa_combo_box); InsertWidgetInTable(hw_table, af_label, af_combo_box); InsertWidgetInTable(hw_table, dither_label, dither_combo_box); InsertWidgetInTable(hw_table, mipmap_label, mipmap_combo_box); InsertWidgetInTable(hw_table, crc_label, crc_combo_box); InsertWidgetInTable(hw_table, acc_bld_label, acc_bld_combo_box); } void populate_gl_table(GtkWidget* gl_table) { GtkWidget* gl_gs_label = left_label("Geometry Shader:"); GtkWidget* gl_gs_combo = CreateComboBoxFromVector(theApp.m_gs_generic_list, "override_geometry_shader"); GtkWidget* gl_ils_label = left_label("Image Load Store:"); GtkWidget* gl_ils_combo = CreateComboBoxFromVector(theApp.m_gs_generic_list, "override_GL_ARB_shader_image_load_store"); GtkWidget* gl_sps_label = left_label("Sparse Texture:"); GtkWidget* gl_sps_combo = CreateComboBoxFromVector(theApp.m_gs_generic_list, "override_GL_ARB_sparse_texture"); AddTooltip(gl_gs_label, gl_gs_combo, IDC_GEOMETRY_SHADER_OVERRIDE); AddTooltip(gl_ils_label, gl_ils_combo, IDC_IMAGE_LOAD_STORE); AddTooltip(gl_sps_label, gl_sps_combo, IDC_SPARSE_TEXTURE); s_table_line = 0; InsertWidgetInTable(gl_table, gl_gs_label, gl_gs_combo); InsertWidgetInTable(gl_table, gl_ils_label, gl_ils_combo); InsertWidgetInTable(gl_table, gl_sps_label, gl_sps_combo); } void populate_sw_table(GtkWidget* sw_table) { GtkWidget* threads_label = left_label("Extra rendering threads:"); GtkWidget* threads_spin = CreateSpinButton(0, 32, "extrathreads"); GtkWidget* aa_check = CreateCheckBox("Edge Anti-aliasing (Del)", "aa1"); GtkWidget* mipmap_check = CreateCheckBox("Mipmapping", "mipmap"); GtkWidget* autoflush_sw_check = CreateCheckBox("Auto Flush", "autoflush_sw"); AddTooltip(aa_check, IDC_AA1); AddTooltip(mipmap_check, IDC_MIPMAP_SW); AddTooltip(autoflush_sw_check, IDC_AUTO_FLUSH_SW); AddTooltip(threads_label, threads_spin, IDC_SWTHREADS); s_table_line = 0; InsertWidgetInTable(sw_table, threads_label, threads_spin); InsertWidgetInTable(sw_table, autoflush_sw_check, aa_check); InsertWidgetInTable(sw_table, mipmap_check); } void populate_shader_table(GtkWidget* shader_table) { GtkWidget* shader = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_OPEN, "Select an external shader", "shaderfx_glsl"); GtkWidget* shader_conf = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_OPEN, "Then select a config", "shaderfx_conf"); GtkWidget* shader_label = left_label("External shader glsl"); GtkWidget* shader_conf_label = left_label("External shader conf"); GtkWidget* shadeboost_check = CreateCheckBox("Shade Boost", "ShadeBoost"); GtkWidget* fxaa_check = CreateCheckBox("Fxaa Shader (PgUp)", "fxaa"); GtkWidget* shaderfx_check = CreateCheckBox("External Shader (Home)", "shaderfx"); GtkWidget* tv_shader_label = left_label("TV Shader:"); GtkWidget* tv_shader = CreateComboBoxFromVector(theApp.m_gs_tv_shaders, "TVShader"); GtkWidget* linear_check = CreateCheckBox("Texture Filtering of Display", "linear_present"); // Shadeboost scale GtkWidget* sb_brightness = CreateScale("ShadeBoost_Brightness"); GtkWidget* sb_brightness_label = left_label("Shade Boost Brightness:"); GtkWidget* sb_contrast = CreateScale("ShadeBoost_Contrast"); GtkWidget* sb_contrast_label = left_label("Shade Boost Contrast:"); GtkWidget* sb_saturation = CreateScale("ShadeBoost_Saturation"); GtkWidget* sb_saturation_label = left_label("Shade Boost Saturation:"); AddTooltip(shadeboost_check, IDC_SHADEBOOST); AddTooltip(shaderfx_check, IDC_SHADER_FX); AddTooltip(fxaa_check, IDC_FXAA); AddTooltip(linear_check, IDC_LINEAR_PRESENT); s_table_line = 0; InsertWidgetInTable(shader_table, linear_check); InsertWidgetInTable(shader_table, fxaa_check); InsertWidgetInTable(shader_table, shadeboost_check); InsertWidgetInTable(shader_table, sb_brightness_label, sb_brightness); InsertWidgetInTable(shader_table, sb_contrast_label, sb_contrast); InsertWidgetInTable(shader_table, sb_saturation_label, sb_saturation); InsertWidgetInTable(shader_table, shaderfx_check); InsertWidgetInTable(shader_table, shader_label, shader); InsertWidgetInTable(shader_table, shader_conf_label, shader_conf); InsertWidgetInTable(shader_table, tv_shader_label, tv_shader); } static GtkWidget* s_hack_skipdraw_offset_spin; static GtkWidget* s_hack_skipdraw_spin; static void CB_SkipdrawRange(GtkSpinButton*, gpointer) { int skipdraw_offset = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(s_hack_skipdraw_offset_spin)); int skipdraw = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(s_hack_skipdraw_spin)); bool skipdraw_offset_changed = skipdraw_offset != theApp.GetConfigI("UserHacks_SkipDraw_Offset"); bool skipdraw_changed = skipdraw != theApp.GetConfigI("UserHacks_SkipDraw"); if (skipdraw_offset == 0 && skipdraw_offset_changed || skipdraw == 0 && skipdraw_changed) { skipdraw_offset = 0; skipdraw = 0; } else if (skipdraw_offset > skipdraw) { if (skipdraw_offset_changed) skipdraw = skipdraw_offset; if (skipdraw_changed) skipdraw_offset = skipdraw; } else if (skipdraw > 0 && skipdraw_offset == 0) { skipdraw_offset = 1; } theApp.SetConfig("UserHacks_SkipDraw_Offset", skipdraw_offset); theApp.SetConfig("UserHacks_SkipDraw", skipdraw); gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_offset_spin), skipdraw_offset); gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_spin), skipdraw); } static void CreateSkipdrawSpinButtons(double min, double max) { s_hack_skipdraw_offset_spin = gtk_spin_button_new_with_range(min, max, 1); s_hack_skipdraw_spin = gtk_spin_button_new_with_range(min, max, 1); gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_offset_spin), theApp.GetConfigI("UserHacks_SkipDraw_Offset")); gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_spin), theApp.GetConfigI("UserHacks_SkipDraw")); g_signal_connect(s_hack_skipdraw_offset_spin, "value-changed", G_CALLBACK(CB_SkipdrawRange), nullptr); g_signal_connect(s_hack_skipdraw_spin, "value-changed", G_CALLBACK(CB_SkipdrawRange), nullptr); } void populate_hack_table(GtkWidget* hack_table) { GtkWidget* hack_offset_label = left_label("Half-pixel Offset:"); GtkWidget* hack_offset_box = CreateComboBoxFromVector(theApp.m_gs_offset_hack, "UserHacks_HalfPixelOffset"); GtkWidget* hack_skipdraw_label = left_label("Skipdraw Range:"); CreateSkipdrawSpinButtons(0, 10000); GtkWidget* hack_wild_check = CreateCheckBox("Wild Arms Hack", "UserHacks_WildHack"); GtkWidget* hack_tco_label = left_label("Texture Offsets:"); GtkWidget* hack_tco_x_spin = CreateSpinButton(0, 10000, "UserHacks_TCOffsetX"); GtkWidget* hack_tco_y_spin = CreateSpinButton(0, 10000, "UserHacks_TCOffsetY"); GtkWidget* align_sprite_check = CreateCheckBox("Align Sprite", "UserHacks_align_sprite_X"); GtkWidget* preload_gs_check = CreateCheckBox("Preload Frame Data", "preload_frame_with_gs_data"); GtkWidget* hack_fast_inv = CreateCheckBox("Fast Texture Invalidation", "UserHacks_DisablePartialInvalidation"); GtkWidget* hack_depth_check = CreateCheckBox("Disable Depth Emulation", "UserHacks_DisableDepthSupport"); GtkWidget* hack_safe_features = CreateCheckBox("Disable Safe Features", "UserHacks_Disable_Safe_Features"); GtkWidget* hack_cpu_fbcv = CreateCheckBox("Frame Buffer Conversion", "UserHacks_CPU_FB_Conversion"); GtkWidget* hack_auto_flush = CreateCheckBox("Auto Flush", "UserHacks_AutoFlush"); GtkWidget* hack_merge_sprite = CreateCheckBox("Merge Sprite", "UserHacks_merge_pp_sprite"); GtkWidget* hack_wrap_mem = CreateCheckBox("Memory Wrapping", "wrap_gs_mem"); GtkWidget* stretch_hack_box = CreateComboBoxFromVector(theApp.m_gs_hack, "UserHacks_round_sprite_offset"); GtkWidget* stretch_hack_label = left_label("Round Sprite:"); GtkWidget* trilinear_box = CreateComboBoxFromVector(theApp.m_gs_trifilter, "UserHacks_TriFilter"); GtkWidget* trilinear_label = left_label("Trilinear Filtering:"); GtkWidget* half_screen_ts_box = CreateComboBoxFromVector(theApp.m_gs_generic_list, "UserHacks_Half_Bottom_Override"); GtkWidget* half_screen_ts_label = left_label("Half-screen Fix:"); // Reuse windows helper string :) AddTooltip(hack_offset_label, IDC_OFFSETHACK); AddTooltip(hack_offset_box, IDC_OFFSETHACK); AddTooltip(hack_skipdraw_label, IDC_SKIPDRAWHACK); AddTooltip(s_hack_skipdraw_offset_spin, IDC_SKIPDRAWHACK); AddTooltip(s_hack_skipdraw_spin, IDC_SKIPDRAWHACK); AddTooltip(hack_wild_check, IDC_WILDHACK); AddTooltip(hack_tco_label, IDC_TCOFFSETX); AddTooltip(hack_tco_x_spin, IDC_TCOFFSETX); AddTooltip(hack_tco_y_spin, IDC_TCOFFSETX); AddTooltip(align_sprite_check, IDC_ALIGN_SPRITE); AddTooltip(stretch_hack_label, stretch_hack_box, IDC_ROUND_SPRITE); AddTooltip(preload_gs_check, IDC_PRELOAD_GS); AddTooltip(hack_fast_inv, IDC_FAST_TC_INV); AddTooltip(hack_depth_check, IDC_TC_DEPTH); AddTooltip(hack_cpu_fbcv, IDC_CPU_FB_CONVERSION); AddTooltip(hack_auto_flush, IDC_AUTO_FLUSH_HW); AddTooltip(hack_safe_features, IDC_SAFE_FEATURES); AddTooltip(hack_merge_sprite, IDC_MERGE_PP_SPRITE); AddTooltip(hack_wrap_mem, IDC_MEMORY_WRAPPING); AddTooltip(trilinear_box, IDC_TRI_FILTER); AddTooltip(trilinear_label, IDC_TRI_FILTER); AddTooltip(half_screen_ts_box, IDC_HALF_SCREEN_TS); AddTooltip(half_screen_ts_label, IDC_HALF_SCREEN_TS); s_table_line = 0; // Hacks // Column one and two HW Hacks InsertWidgetInTable(hack_table, align_sprite_check, hack_cpu_fbcv); InsertWidgetInTable(hack_table, hack_auto_flush, hack_wrap_mem); InsertWidgetInTable(hack_table, hack_depth_check, hack_merge_sprite); InsertWidgetInTable(hack_table, hack_safe_features, preload_gs_check); InsertWidgetInTable(hack_table, hack_fast_inv, hack_wild_check); // Other hacks InsertWidgetInTable(hack_table, half_screen_ts_label, half_screen_ts_box); InsertWidgetInTable(hack_table, trilinear_label, trilinear_box); InsertWidgetInTable(hack_table, hack_offset_label, hack_offset_box); InsertWidgetInTable(hack_table, stretch_hack_label, stretch_hack_box); InsertWidgetInTable(hack_table, hack_skipdraw_label, s_hack_skipdraw_offset_spin, s_hack_skipdraw_spin); InsertWidgetInTable(hack_table, hack_tco_label, hack_tco_x_spin, hack_tco_y_spin); } void populate_main_table(GtkWidget* main_table) { GtkWidget* render_label = left_label("Renderer:"); GtkWidget* render_combo_box = CreateComboBoxFromVector(theApp.m_gs_renderers, "Renderer"); GtkWidget* interlace_label = left_label("Interlacing (F5):"); GtkWidget* interlace_combo_box = CreateComboBoxFromVector(theApp.m_gs_interlace, "interlace"); GtkWidget* filter_label = left_label("Texture Filtering:"); GtkWidget* filter_combo_box = CreateComboBoxFromVector(theApp.m_gs_bifilter, "filter"); AddTooltip(filter_label, filter_combo_box, IDC_FILTER); s_table_line = 0; InsertWidgetInTable(main_table, render_label, render_combo_box); InsertWidgetInTable(main_table, interlace_label, interlace_combo_box); InsertWidgetInTable(main_table, filter_label, filter_combo_box); } void populate_debug_table(GtkWidget* debug_table) { GtkWidget* glsl_debug_check = CreateCheckBox("GLSL compilation", "debug_glsl_shader"); GtkWidget* gl_debug_check = CreateCheckBox("Print GL error", "debug_opengl"); GtkWidget* gs_dump_check = CreateCheckBox("Dump GS data", "dump"); GtkWidget* gs_save_check = CreateCheckBox("Save RT", "save"); GtkWidget* gs_savef_check = CreateCheckBox("Save Frame", "savef"); GtkWidget* gs_savet_check = CreateCheckBox("Save Texture", "savet"); GtkWidget* gs_savez_check = CreateCheckBox("Save Depth", "savez"); GtkWidget* gs_saven_label = left_label("Start of Dump"); GtkWidget* gs_saven_spin = CreateSpinButton(0, pow(10, 9), "saven"); GtkWidget* gs_savel_label = left_label("Length of Dump"); GtkWidget* gs_savel_spin = CreateSpinButton(0, pow(10, 5), "savel"); s_table_line = 0; InsertWidgetInTable(debug_table, gl_debug_check, glsl_debug_check); InsertWidgetInTable(debug_table, gs_dump_check); InsertWidgetInTable(debug_table, gs_save_check, gs_savef_check); InsertWidgetInTable(debug_table, gs_savet_check, gs_savez_check); InsertWidgetInTable(debug_table, gs_saven_label, gs_saven_spin); InsertWidgetInTable(debug_table, gs_savel_label, gs_savel_spin); } void populate_record_table(GtkWidget* record_table) { GtkWidget* capture_check = CreateCheckBox("Enable Recording (with F12)", "capture_enabled"); GtkWidget* resxy_label = left_label("Resolution:"); GtkWidget* resx_spin = CreateSpinButton(256, 8192, "CaptureWidth"); GtkWidget* resy_spin = CreateSpinButton(256, 8192, "CaptureHeight"); GtkWidget* threads_label = left_label("Saving Threads:"); GtkWidget* threads_spin = CreateSpinButton(1, 32, "capture_threads"); GtkWidget* out_dir_label = left_label("Output Directory:"); GtkWidget* out_dir = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "Select a directory", "capture_out_dir"); GtkWidget* png_label = left_label("PNG Compression Level:"); GtkWidget* png_level = CreateSpinButton(1, 9, "png_compression_level"); InsertWidgetInTable(record_table, capture_check); InsertWidgetInTable(record_table, resxy_label, resx_spin, resy_spin); InsertWidgetInTable(record_table, threads_label, threads_spin); InsertWidgetInTable(record_table, png_label, png_level); InsertWidgetInTable(record_table, out_dir_label, out_dir); } void populate_osd_table(GtkWidget* osd_table) { GtkWidget* monitor_check = CreateCheckBox("Enable Monitor", "osd_monitor_enabled"); GtkWidget* log_check = CreateCheckBox("Enable Log", "osd_log_enabled"); GtkWidget* fontsize_label = left_label("Size:"); GtkWidget* fontsize_text = CreateSpinButton(1, 100, "osd_fontsize"); GtkWidget* osd_red_label = left_label("Red:"); GtkWidget* osd_red_spin = CreateScale("osd_color_r", 0, 255, 1); GtkWidget* osd_green_label = left_label("Green:"); GtkWidget* osd_green_spin = CreateScale("osd_color_g", 0, 255, 1); GtkWidget* osd_blue_label = left_label("Blue:"); GtkWidget* osd_blue_spin = CreateScale("osd_color_b", 0, 255, 1); GtkWidget* opacity_label = left_label("Opacity:"); GtkWidget* opacity_slide = CreateScale("osd_color_opacity"); GtkWidget* log_timeout_label = left_label("Timeout (seconds):"); GtkWidget* log_timeout_text = CreateSpinButton(2, 10, "osd_log_timeout"); GtkWidget* max_messages_label = left_label("Maximum Onscreen Log Messages:"); GtkWidget* max_messages_spin = CreateSpinButton(1, 20, "osd_max_log_messages"); AddTooltip(log_check, IDC_OSD_LOG); AddTooltip(monitor_check, IDC_OSD_MONITOR); AddTooltip(max_messages_label, max_messages_spin, IDC_OSD_MAX_LOG); InsertWidgetInTable(osd_table, monitor_check, log_check); InsertWidgetInTable(osd_table, fontsize_label, fontsize_text); InsertWidgetInTable(osd_table, osd_red_label, osd_red_spin); InsertWidgetInTable(osd_table, osd_green_label, osd_green_spin); InsertWidgetInTable(osd_table, osd_blue_label, osd_blue_spin); InsertWidgetInTable(osd_table, opacity_label, opacity_slide); InsertWidgetInTable(osd_table, log_timeout_label, log_timeout_text); InsertWidgetInTable(osd_table, max_messages_label, max_messages_spin); } GtkWidget* ScrollMe(GtkWidget* w) { // the scrolled window add an ugly outline/border even when the scroll bar is off. if (BigEnough()) return w; GtkWidget* scrollbar = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbar), GTK_SHADOW_NONE); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbar), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); #if GTK_CHECK_VERSION(3, 22, 0) gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrollbar), true); #endif #if GTK_CHECK_VERSION(3, 8, 0) gtk_container_add(GTK_CONTAINER(scrollbar), w); #else gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollbar), w); #endif return scrollbar; } bool RunLinuxDialog() { GtkWidget* dialog; int return_value; /* Create the widgets */ dialog = gtk_dialog_new_with_buttons( "GSdx Config", NULL, /* parent window*/ (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), "OK", GTK_RESPONSE_ACCEPT, // "Cancel", GTK_RESPONSE_REJECT, // Drop because it is too annoying to support call back this way NULL); // The main area for the whole dialog box. GtkWidget* main_box = CreateVbox(); GtkWidget* central_box = CreateVbox(); GtkWidget* advanced_box = CreateVbox(); GtkWidget* debug_box = CreateVbox(); GtkWidget* shader_box = CreateVbox(); GtkWidget* osd_box = CreateVbox(); // Grab a logo, to make things look nice. if (BigEnough()) { GResource* resources = GSdx_res_get_resource(); GInputStream* ogl_stream = g_resource_open_stream(resources, "/GSdx/res/logo-ogl.bmp", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); GdkPixbuf* ogl_logo = gdk_pixbuf_new_from_stream(ogl_stream, NULL, NULL); g_object_unref(ogl_stream); GtkWidget* logo_image = gtk_image_new_from_pixbuf(ogl_logo); gtk_box_pack_start(GTK_BOX(main_box), logo_image, true, true, 0); } GtkWidget* main_table = CreateTableInBox(main_box, NULL, 2, 2); GtkWidget* hw_table = CreateTableInBox(central_box, "Hardware Mode Settings", 7, 2); GtkWidget* sw_table = CreateTableInBox(central_box, "Software Mode Settings", 2, 2); GtkWidget* hack_table = CreateTableInBox(advanced_box, "Hacks", 7, 2); GtkWidget* gl_table = CreateTableInBox(advanced_box, "OpenGL Very Advanced Custom Settings", 6, 2); GtkWidget* record_table = CreateTableInBox(debug_box, "Recording Settings", 4, 3); GtkWidget* debug_table = CreateTableInBox(debug_box, "OpenGL / GSdx Debug Settings", 6, 3); GtkWidget* shader_table = CreateTableInBox(shader_box, "Custom Shader Settings", 9, 2); GtkWidget* osd_table = CreateTableInBox(osd_box, "OSD", 6, 2); // Populate all the tables populate_main_table(main_table); populate_shader_table(shader_table); populate_hw_table(hw_table); populate_sw_table(sw_table); populate_hack_table(hack_table); populate_gl_table(gl_table); populate_debug_table(debug_table); populate_record_table(record_table); populate_osd_table(osd_table); // Handle some nice tabs GtkWidget* notebook = gtk_notebook_new(); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(central_box), gtk_label_new("Renderer Settings")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(advanced_box), gtk_label_new("Advanced Settings")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(debug_box), gtk_label_new("Debug/Recording")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(shader_box), gtk_label_new("Post-Processing")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(osd_box), gtk_label_new("OSD")); // Put everything in the big box. gtk_container_add(GTK_CONTAINER(main_box), notebook); // Enable/disable hack frame based on enable option s_hack_frame = hack_table; gtk_widget_set_sensitive(s_hack_frame, theApp.GetConfigB("UserHacks")); // Put the box in the dialog and show it to the world. gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_box); gtk_widget_show_all(dialog); return_value = gtk_dialog_run(GTK_DIALOG(dialog)); // Compatibility & not supported option int mode_width = theApp.GetConfigI("ModeWidth"); int mode_height = theApp.GetConfigI("ModeHeight"); theApp.SetConfig("ModeHeight", mode_height); theApp.SetConfig("ModeWidth", mode_width); theApp.SetConfig("windowed", 1); gtk_widget_destroy(dialog); return (return_value == GTK_RESPONSE_ACCEPT); }