X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fgtkmisc.cpp;h=59dab2a9187265a454ad75883178f2d941b8f259;hb=b5391544e08298842dc61947979da08a89e0a26e;hp=394e3928091d2fc489a4688b3f102d53c03f90bd;hpb=830125fad042fad35dc029b6eb57c8156ad7e176;p=xonotic%2Fnetradiant.git diff --git a/radiant/gtkmisc.cpp b/radiant/gtkmisc.cpp index 394e3928..59dab2a9 100644 --- a/radiant/gtkmisc.cpp +++ b/radiant/gtkmisc.cpp @@ -32,1451 +32,75 @@ // Small functions to help with GTK // -#include -#include +#include "gtkmisc.h" -#if defined ( __linux__ ) || defined ( __APPLE__ ) -#include -#endif +#include +#include -#include +#include "math/vector.h" +#include "os/path.h" -#ifdef _WIN32 -#include -#define WIN32_LEAN_AND_MEAN -#include -#endif +#include "gtkutil/dialog.h" +#include "gtkutil/filechooser.h" +#include "gtkutil/menu.h" +#include "gtkutil/toolbar.h" +#include "commands.h" - -#ifdef _WIN32 -#include -#include -#define R_OK 04 -#endif -#include "stdafx.h" - // ============================================================================= // Misc stuff -// NOTE TTimo window position saving has always been tricky -// it doesn't work the same between win32 and linux .. see below that code is fairly different -// it's also very poorly done, the save calls are a bit randomly disctributed in the OnDestroy - -void save_window_pos( GtkWidget *wnd, window_position_t& pos ){ - if ( ( wnd == NULL ) || ( wnd->window == NULL ) ) { - return; - } - - get_window_pos( wnd, &pos.x, &pos.y ); - - pos.w = wnd->allocation.width; - pos.h = wnd->allocation.height; - -#ifdef DBG_WINDOWPOS - //Sys_Printf("save_window_pos 'Window %s'\n",buf); -#endif -} - -#ifdef _WIN32 -void win32_get_window_pos( GtkWidget *widget, gint *x, gint *y ){ - if ( g_PrefsDlg.m_bStartOnPrimMon ) { - RECT rc; - POINT point; - HWND xwnd = (HWND)GDK_WINDOW_HWND( widget->window ); - const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); - - GetClientRect( xwnd,&rc ); - point.x = rc.left; - point.y = rc.top; - ClientToScreen( xwnd,&point ); - - *x = point.x; - *y = point.y; - - *x = max( *x,-widget->allocation.width + 10 ); - *x = min( *x,primaryMonitorRect.width - 10 ); - *y = max( *y,-widget->allocation.height + 10 ); - *y = min( *y,primaryMonitorRect.height - 10 ); - } - else { - // this is the same as the unix version of get_window_pos - gdk_window_get_root_origin( widget->window, x, y ); - } -#ifdef DBG_WINDOWPOS - Sys_Printf( "win32_get_window_pos %p %d,%d\n",widget,*x,*y ); -#endif -} -#endif - -void load_window_pos( GtkWidget *wnd, window_position_t& pos ){ -#ifdef _WIN32 - const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); - - if ( pos.x < primaryMonitorRect.x - || pos.y < primaryMonitorRect.y - || pos.x > primaryMonitorRect.x + primaryMonitorRect.width - || pos.y > primaryMonitorRect.y + primaryMonitorRect.height ) { - gtk_window_set_position( GTK_WINDOW( wnd ), GTK_WIN_POS_CENTER_ON_PARENT ); - } -#else - // FIXME: not multihead safe - if ( pos.x < 0 - || pos.y < 0 - || pos.x > gdk_screen_width() - || pos.y > gdk_screen_height() ) { - gtk_window_set_position( GTK_WINDOW( wnd ), GTK_WIN_POS_CENTER_ON_PARENT ); - } -#endif - else{ - gtk_window_move( GTK_WINDOW( wnd ), pos.x, pos.y ); - } - - gtk_window_set_default_size( GTK_WINDOW( wnd ), pos.w, pos.h ); -#ifdef DBG_WINDOWPOS - Sys_Printf( "load_window_pos %p 'Window,%s'\n",wnd,windowData ); -#endif -} - -gint widget_delete_hide( GtkWidget *widget ){ - gtk_widget_hide( widget ); - - return TRUE; -} - - -// Thanks to Mercury, Fingolfin - ETG -int readLongLE( FILE *file, unsigned long *m_bytesRead, int *value ){ - byte buf[4]; - int len = fread( buf, 4, 1, file ); - *m_bytesRead += 4; - if ( len != 1 ) { - return -1; - } - - *value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; - return 0; -} - -short readShortLE( FILE *file, unsigned long *m_bytesRead, short unsigned *value ){ - byte buf[2]; - int len = fread( buf, 2, 1, file ); - *m_bytesRead += 2; - if ( len != 1 ) { - return -1; - } - - *value = buf[0] | buf[1] << 8; - return 0; -} - -unsigned char *load_bitmap_file( const char* filename, guint16 *width, guint16 *height ){ - int bmWidth, bmHeight; - short unsigned bmPlanes, bmBitsPixel; - typedef struct { - unsigned char rgbBlue; - unsigned char rgbGreen; - unsigned char rgbRed; - unsigned char rgbReserved; - } RGBQUAD; - unsigned char m1,m2; - int sizeimage; - short unsigned res1,res2; - int filesize, pixoff; - int bmisize, compression; - int xscale, yscale; - int colors, impcol; - unsigned long m_bytesRead = 0; - unsigned char *imagebits = NULL; - FILE *fp; - - *width = *height = 0; - - fp = fopen( filename,"rb" ); - if ( fp == NULL ) { - return NULL; - } - - size_t rc; - rc = fread( &m1, 1, 1, fp ); - m_bytesRead++; - if ( rc == -1 ) { - fclose( fp ); - return NULL; - } - - rc = fread( &m2, 1, 1, fp ); - m_bytesRead++; - if ( ( m1 != 'B' ) || ( m2 != 'M' ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&filesize ) ) { - fclose( fp ); - return NULL; - } - - if ( readShortLE( fp,&m_bytesRead,&res1 ) ) { - fclose( fp ); - return NULL; - } - - if ( readShortLE( fp,&m_bytesRead,&res2 ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&pixoff ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&bmisize ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&bmWidth ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&bmHeight ) ) { - fclose( fp ); - return NULL; - } - - if ( readShortLE( fp,&m_bytesRead,&bmPlanes ) ) { - fclose( fp ); - return NULL; - } - - if ( readShortLE( fp,&m_bytesRead,&bmBitsPixel ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&compression ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&sizeimage ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&xscale ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&yscale ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&colors ) ) { - fclose( fp ); - return NULL; - } - - if ( readLongLE( fp,&m_bytesRead,&impcol ) ) { - fclose( fp ); - return NULL; - } - - if ( colors == 0 ) { - colors = 1 << bmBitsPixel; - } - - RGBQUAD *colormap = NULL; - if ( bmBitsPixel != 24 ) { - colormap = new RGBQUAD[colors]; - if ( colormap == NULL ) { - fclose( fp ); - return NULL; - } - - int i; - for ( i = 0; i < colors; i++ ) - { - unsigned char r,g, b, dummy; - - rc = fread( &b, 1, 1, fp ); - m_bytesRead++; - if ( rc != 1 ) { - delete [] colormap; - fclose( fp ); - return NULL; - } - - rc = fread( &g, 1, 1, fp ); - m_bytesRead++; - if ( rc != 1 ) { - delete [] colormap; - fclose( fp ); - return NULL; - } - - rc = fread( &r, 1, 1, fp ); - m_bytesRead++; - if ( rc != 1 ) { - delete [] colormap; - fclose( fp ); - return NULL; - } - - rc = fread( &dummy, 1, 1, fp ); - m_bytesRead++; - if ( rc != 1 ) { - delete [] colormap; - fclose( fp ); - return NULL; - } - - colormap[i].rgbRed = r; - colormap[i].rgbGreen = g; - colormap[i].rgbBlue = b; - } - } - - if ( (long)m_bytesRead > pixoff ) { - delete [] colormap; - fclose( fp ); - return NULL; - } - - while ( (long)m_bytesRead < pixoff ) - { - char dummy; - fread( &dummy,1,1,fp ); - m_bytesRead++; - } - - int w = bmWidth; - int h = bmHeight; - - // set the output params - imagebits = (unsigned char *)malloc( w * h * 3 ); - long row_size = w * 3; - - if ( imagebits != NULL ) { - *width = w; - *height = h; - unsigned char *outbuf = imagebits; - long row = 0; - long rowOffset = 0; - - if ( compression == 0 ) { // BI_RGB - // read rows in reverse order - for ( row = bmHeight - 1; row >= 0; row-- ) - { - // which row are we working on? - rowOffset = (long unsigned)row * row_size; - - if ( bmBitsPixel == 24 ) { - for ( int col = 0; col < w; col++ ) - { - long offset = col * 3; - char pixel[3]; - - if ( fread( (void *)( pixel ),1,3,fp ) == 3 ) { - // we swap red and blue here - *( outbuf + rowOffset + offset + 0 ) = pixel[2]; // r - *( outbuf + rowOffset + offset + 1 ) = pixel[1]; // g - *( outbuf + rowOffset + offset + 2 ) = pixel[0]; // b - } - } - m_bytesRead += row_size; - - // read DWORD padding - while ( ( m_bytesRead - pixoff ) & 3 ) - { - char dummy; - if ( fread( &dummy,1,1,fp ) != 1 ) { - free( imagebits ); - fclose( fp ); - return NULL; - } - m_bytesRead++; - } - } - else - { - // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them - int bit_count = 0; - unsigned long mask = ( 1 << bmBitsPixel ) - 1; - unsigned char inbyte = 0; - - for ( int col = 0; col < w; col++ ) - { - int pix = 0; - - // if we need another byte - if ( bit_count <= 0 ) { - bit_count = 8; - if ( fread( &inbyte,1,1,fp ) != 1 ) { - free( imagebits ); - delete [] colormap; - fclose( fp ); - return NULL; - } - m_bytesRead++; - } - - // keep track of where we are in the bytes - bit_count -= bmBitsPixel; - pix = ( inbyte >> bit_count ) & mask; - - // lookup the color from the colormap - stuff it in our buffer - // swap red and blue - *( outbuf + rowOffset + col * 3 + 2 ) = colormap[pix].rgbBlue; - *( outbuf + rowOffset + col * 3 + 1 ) = colormap[pix].rgbGreen; - *( outbuf + rowOffset + col * 3 + 0 ) = colormap[pix].rgbRed; - } - - // read DWORD padding - while ( ( m_bytesRead - pixoff ) & 3 ) - { - char dummy; - if ( fread( &dummy,1,1,fp ) != 1 ) { - free( imagebits ); - if ( colormap ) { - delete [] colormap; - } - fclose( fp ); - return NULL; - } - m_bytesRead++; - } - } - } - } - else - { - int i, x = 0; - unsigned char c, c1 = 0, *pp; - row = 0; - pp = outbuf + ( bmHeight - 1 ) * bmWidth * 3; - - if ( bmBitsPixel == 8 ) { - while ( row < bmHeight ) - { - c = getc( fp ); - - if ( c ) { - // encoded mode - c1 = getc( fp ); - for ( i = 0; i < c; x++, i++ ) - { - *pp = colormap[c1].rgbRed; pp++; - *pp = colormap[c1].rgbGreen; pp++; - *pp = colormap[c1].rgbBlue; pp++; - } - } - else - { - // c==0x00, escape codes - c = getc( fp ); - if ( c == 0x00 ) { // end of line - row++; - x = 0; - pp = outbuf + ( bmHeight - row - 1 ) * bmWidth * 3; - } - else if ( c == 0x01 ) { - break; // end of pic - } - else if ( c == 0x02 ) { // delta - c = getc( fp ); - x += c; - c = getc( fp ); - row += c; - pp = outbuf + x * 3 + ( bmHeight - row - 1 ) * bmWidth * 3; - } - else // absolute mode - { - for ( i = 0; i < c; x++, i++ ) - { - c1 = getc( fp ); - *pp = colormap[c1].rgbRed; pp++; - *pp = colormap[c1].rgbGreen; pp++; - *pp = colormap[c1].rgbBlue; pp++; - } - - if ( c & 1 ) { - getc( fp ); // odd length run: read an extra pad byte - } - } - } - } - } - else if ( bmBitsPixel == 4 ) { - while ( row < bmHeight ) - { - c = getc( fp ); - - if ( c ) { - // encoded mode - c1 = getc( fp ); - for ( i = 0; i < c; x++, i++ ) - { - *pp = colormap[( i & 1 ) ? ( c1 & 0x0f ) : ( ( c1 >> 4 ) & 0x0f )].rgbRed; pp++; - *pp = colormap[( i & 1 ) ? ( c1 & 0x0f ) : ( ( c1 >> 4 ) & 0x0f )].rgbGreen; pp++; - *pp = colormap[( i & 1 ) ? ( c1 & 0x0f ) : ( ( c1 >> 4 ) & 0x0f )].rgbBlue; pp++; - } - } - else - { - // c==0x00, escape codes - c = getc( fp ); - - if ( c == 0x00 ) { // end of line - row++; - x = 0; - pp = outbuf + ( bmHeight - row - 1 ) * bmWidth * 3; - } - else if ( c == 0x01 ) { - break; // end of pic - } - else if ( c == 0x02 ) { // delta - c = getc( fp ); - x += c; - c = getc( fp ); - row += c; - pp = outbuf + x * 3 + ( bmHeight - row - 1 ) * bmWidth * 3; - } - else // absolute mode - { - for ( i = 0; i < c; x++, i++ ) - { - if ( ( i & 1 ) == 0 ) { - c1 = getc( fp ); - } - *pp = colormap[( i & 1 ) ? ( c1 & 0x0f ) : ( ( c1 >> 4 ) & 0x0f )].rgbRed; pp++; - *pp = colormap[( i & 1 ) ? ( c1 & 0x0f ) : ( ( c1 >> 4 ) & 0x0f )].rgbGreen; pp++; - *pp = colormap[( i & 1 ) ? ( c1 & 0x0f ) : ( ( c1 >> 4 ) & 0x0f )].rgbBlue; pp++; - } - - if ( ( ( c & 3 ) == 1 ) || ( ( c & 3 ) == 2 ) ) { - getc( fp ); // odd length run: read an extra pad byte - } - } - } - } - } - } - if ( colormap ) { - delete [] colormap; - } - - fclose( fp ); - } - return imagebits; -} - -void bmp_to_pixmap( const char* filename, GdkPixmap **pixmap, GdkBitmap **mask ){ - guint16 width, height; - unsigned char *buf; - GdkWindow *window = gdk_get_default_root_window(); - GdkColormap *colormap; - GdkGC* gc = gdk_gc_new( window ); - int i, j; - bool hasMask = false; - - *pixmap = *mask = NULL; - buf = load_bitmap_file( filename, &width, &height ); - if ( !buf ) { - return; - } - - colormap = gdk_drawable_get_colormap( window ); - *pixmap = gdk_pixmap_new( window, width, height, -1 ); - - typedef struct - { - GdkColor c; - unsigned char *p; - } PAL; - - for ( i = 0; i < height; i++ ) - { - for ( j = 0; j < width; j++ ) - { - unsigned char *p = &buf[( i * width + j ) * 3]; - PAL pe; - - pe.c.red = (gushort)( p[0] * 0xFF ); - pe.c.green = (gushort)( p[1] * 0xFF ); - pe.c.blue = (gushort)( p[2] * 0xFF ); - gdk_colormap_alloc_color( colormap, &pe.c, FALSE, TRUE ); - gdk_gc_set_foreground( gc, &pe.c ); - gdk_draw_point( *pixmap, gc, j, i ); - - if ( p[0] == 0xFF && p[1] == 0x00 && p[2] == 0xFF ) { - hasMask = true; - } - } - } - - gdk_gc_unref( gc ); - *mask = gdk_pixmap_new( window, width, height, 1 ); - gc = gdk_gc_new( *mask ); - if ( hasMask ) { - for ( i = 0; i < height; i++ ) - { - for ( j = 0; j < width; j++ ) - { - GdkColor mask_pattern; - - // pink is transparent - if ( ( buf[( i * width + j ) * 3] == 0xff ) && - ( buf[( i * width + j ) * 3 + 1] == 0x00 ) && - ( buf[( i * width + j ) * 3 + 2] == 0xff ) ) { - mask_pattern.pixel = 0; - } - else{ - mask_pattern.pixel = 1; - } - - gdk_gc_set_foreground( gc, &mask_pattern ); - // possible Win32 Gtk bug here - //gdk_draw_point (*mask, gc, j, i); - gdk_draw_line( *mask, gc, j, i, j + 1, i ); - } - } - } - else - { - GdkColor mask_pattern; - mask_pattern.pixel = 1; - gdk_gc_set_foreground( gc, &mask_pattern ); - gdk_draw_rectangle( *mask, gc, 1, 0, 0, width, height ); - } - gdk_gc_unref( gc ); - free( buf ); -} - -void load_pixmap( const char* filename, GtkWidget* widget, GdkPixmap **gdkpixmap, GdkBitmap **mask ){ - CString str; - - str = g_strBitmapsPath; - str += filename; - - bmp_to_pixmap( str.GetBuffer(), gdkpixmap, mask ); - if ( *gdkpixmap == NULL ) { - printf( "gdkpixmap was null\n" ); - gchar *dummy[] = { "1 1 1 1", " c None", " " }; - printf( "calling gdk_pixmap_create_from_xpm_d\n" ); - *gdkpixmap = gdk_pixmap_create_from_xpm_d( gdk_get_default_root_window(), mask, NULL, dummy ); - } -} - -// this is the same as above but used by the plugins -// GdkPixmap **gdkpixmap, GdkBitmap **mask -bool WINAPI load_plugin_bitmap( const char* filename, void **gdkpixmap, void **mask ){ - CString str; - - str = g_strGameToolsPath; - str += g_strPluginsDir; - str += "bitmaps/"; - str += filename; - bmp_to_pixmap( str.GetBuffer(), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask ); - - if ( *gdkpixmap == NULL ) { - // look in the core plugins - str = g_strAppPath; - str += g_strPluginsDir; - str += "bitmaps/"; - str += filename; - bmp_to_pixmap( str.GetBuffer(), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask ); - - if ( *gdkpixmap == NULL ) { - - // look in core modules - str = g_strAppPath; - str += g_strModulesDir; - str += "bitmaps/"; - str += filename; - bmp_to_pixmap( str.GetBuffer(), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask ); - - if ( *gdkpixmap == NULL ) { - gchar *dummy[] = { "1 1 1 1", " c None", " " }; - *gdkpixmap = gdk_pixmap_create_from_xpm_d( gdk_get_default_root_window(), (GdkBitmap **)mask, NULL, dummy ); - return false; - } - } - } - return true; -} - -// Load a xpm file and return a pixmap widget. -GtkWidget* new_pixmap( GtkWidget* widget, const char* filename ){ - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - - load_pixmap( filename, widget, &gdkpixmap, &mask ); - pixmap = gtk_pixmap_new( gdkpixmap, mask ); - - gdk_drawable_unref( gdkpixmap ); - gdk_drawable_unref( mask ); - - return pixmap; -} - -// ============================================================================= -// Menu stuff - -GtkWidget* menu_separator( GtkWidget *menu ){ - GtkWidget *menu_item = gtk_menu_item_new(); - gtk_menu_append( GTK_MENU( menu ), menu_item ); - gtk_widget_set_sensitive( menu_item, FALSE ); - gtk_widget_show( menu_item ); - return menu_item; -} - -GtkWidget* menu_tearoff( GtkWidget *menu ){ - GtkWidget *menu_item = gtk_tearoff_menu_item_new(); - gtk_menu_append( GTK_MENU( menu ), menu_item ); -// gtk_widget_set_sensitive (menu_item, FALSE); -- controls whether menu is detachable - gtk_widget_show( menu_item ); - return menu_item; -} - -GtkWidget* create_sub_menu_with_mnemonic( GtkWidget *bar, const gchar *mnemonic ){ - GtkWidget *item, *sub_menu; - - item = gtk_menu_item_new_with_mnemonic( mnemonic ); - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( bar ), item ); - - sub_menu = gtk_menu_new(); - gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), sub_menu ); - - return sub_menu; -} - -extern void AddMenuItem( GtkWidget* menu, unsigned int id ); - -GtkWidget* create_menu_item_with_mnemonic( GtkWidget *menu, const gchar *mnemonic, GtkSignalFunc func, int id ){ - GtkWidget *item; - - item = gtk_menu_item_new_with_mnemonic( mnemonic ); - - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - gtk_signal_connect( GTK_OBJECT( item ), "activate", GTK_SIGNAL_FUNC( func ), GINT_TO_POINTER( id ) ); - - AddMenuItem( item, id ); - return item; +void command_connect_accelerator( const char* name ){ + const Command& command = GlobalCommands_find( name ); + GlobalShortcuts_register( name, 1 ); + global_accel_group_connect( command.m_accelerator, command.m_callback ); } -GtkWidget* create_check_menu_item_with_mnemonic( GtkWidget *menu, const gchar *mnemonic, GtkSignalFunc func, int id, gboolean active ){ - GtkWidget *item; - - item = gtk_check_menu_item_new_with_mnemonic( mnemonic ); - - gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( item ), active ); - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - gtk_signal_connect( GTK_OBJECT( item ), "activate", GTK_SIGNAL_FUNC( func ), GINT_TO_POINTER( id ) ); - - AddMenuItem( item, id ); - return item; +void command_disconnect_accelerator( const char* name ){ + const Command& command = GlobalCommands_find( name ); + global_accel_group_disconnect( command.m_accelerator, command.m_callback ); } -GtkWidget* create_radio_menu_item_with_mnemonic( GtkWidget *menu, GtkWidget *last, const gchar *mnemonic, GtkSignalFunc func, int id, gboolean state ){ - GtkWidget *item; - GSList *group = (GSList*)NULL; - - if ( last != NULL ) { - group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( last ) ); - } - item = gtk_radio_menu_item_new_with_mnemonic( group, mnemonic ); - gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), state ); - - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - gtk_signal_connect( GTK_OBJECT( item ), "activate", GTK_SIGNAL_FUNC( func ), GINT_TO_POINTER( id ) ); - - AddMenuItem( item, id ); - return item; +void toggle_add_accelerator( const char* name ){ + const Toggle& toggle = GlobalToggles_find( name ); + GlobalShortcuts_register( name, 2 ); + global_accel_group_connect( toggle.m_command.m_accelerator, toggle.m_command.m_callback ); } -GtkWidget* create_menu_in_menu_with_mnemonic( GtkWidget *menu, const gchar *mnemonic ){ - GtkWidget *item, *submenu; - - item = gtk_menu_item_new_with_mnemonic( mnemonic ); - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - - submenu = gtk_menu_new(); - gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), submenu ); - - return submenu; +void toggle_remove_accelerator( const char* name ){ + const Toggle& toggle = GlobalToggles_find( name ); + global_accel_group_disconnect( toggle.m_command.m_accelerator, toggle.m_command.m_callback ); } -// ============================================================================= -// Message Boxes - -void dialog_button_callback( GtkWidget *widget, gpointer data ) { - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel( widget ); - loop = (int*)g_object_get_data( G_OBJECT( parent ), "loop" ); - ret = (int*)g_object_get_data( G_OBJECT( parent ), "ret" ); - - *loop = 0; - *ret = GPOINTER_TO_INT( data ); +GtkCheckMenuItem* create_check_menu_item_with_mnemonic( GtkMenu* menu, const char* mnemonic, const char* commandName ){ + GlobalShortcuts_register( commandName, 2 ); + const Toggle& toggle = GlobalToggles_find( commandName ); + global_accel_group_connect( toggle.m_command.m_accelerator, toggle.m_command.m_callback ); + return create_check_menu_item_with_mnemonic( menu, mnemonic, toggle ); } -gint dialog_delete_callback( GtkWidget *widget, GdkEvent* event, gpointer data ){ - int *loop; - - gtk_widget_hide( widget ); - loop = (int*)g_object_get_data( G_OBJECT( widget ), "loop" ); - *loop = 0; - - return TRUE; +GtkMenuItem* create_menu_item_with_mnemonic( GtkMenu* menu, const char *mnemonic, const char* commandName ){ + GlobalShortcuts_register( commandName, 1 ); + const Command& command = GlobalCommands_find( commandName ); + global_accel_group_connect( command.m_accelerator, command.m_callback ); + return create_menu_item_with_mnemonic( menu, mnemonic, command ); } -gint dialog_url_callback( GtkWidget *widget, GdkEvent* event, gpointer data ){ - OpenURL( (const char *)g_object_get_data( G_OBJECT( widget ), "URL" ) ); - - return TRUE; +GtkButton* toolbar_append_button( GtkToolbar* toolbar, const char* description, const char* icon, const char* commandName ){ + return toolbar_append_button( toolbar, description, icon, GlobalCommands_find( commandName ) ); } -int WINAPI gtk_MessageBox( void *parent, const char* lpText, const char* lpCaption, guint32 uType, const char* URL ){ - GtkWidget *window, *w, *vbox, *hbox; - GtkAccelGroup *accel; - int mode = ( uType & MB_TYPEMASK ), ret, loop = 1; - - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - gtk_signal_connect( GTK_OBJECT( window ), "delete_event", - GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); - gtk_signal_connect( GTK_OBJECT( window ), "destroy", - GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); - gtk_window_set_title( GTK_WINDOW( window ), lpCaption ); - gtk_container_border_width( GTK_CONTAINER( window ), 10 ); - g_object_set_data( G_OBJECT( window ), "loop", &loop ); - g_object_set_data( G_OBJECT( window ), "ret", &ret ); - gtk_widget_realize( window ); - - gtk_window_set_policy( GTK_WINDOW( window ),FALSE,FALSE,TRUE ); - - if ( parent != NULL ) { - gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( parent ) ); - } - - accel = gtk_accel_group_new(); - gtk_window_add_accel_group( GTK_WINDOW( window ), accel ); - - vbox = gtk_vbox_new( FALSE, 10 ); - gtk_container_add( GTK_CONTAINER( window ), vbox ); - gtk_widget_show( vbox ); - - w = gtk_label_new( lpText ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 2 ); - gtk_label_set_justify( GTK_LABEL( w ), GTK_JUSTIFY_LEFT ); - gtk_widget_show( w ); - - w = gtk_hseparator_new(); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 2 ); - gtk_widget_show( w ); - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 2 ); - gtk_widget_show( hbox ); - - if ( mode == MB_OK ) { - w = gtk_button_new_with_label( _( "Ok" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); - gtk_widget_add_accelerator( w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 ); - gtk_widget_add_accelerator( w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - ret = IDOK; - } - else if ( mode == MB_OKCANCEL ) { - w = gtk_button_new_with_label( _( "Ok" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); - gtk_widget_add_accelerator( w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( _( "Cancel" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); - gtk_widget_add_accelerator( w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 ); - gtk_widget_show( w ); - ret = IDCANCEL; - } - else if ( mode == MB_YESNOCANCEL ) { - w = gtk_button_new_with_label( _( "Yes" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDYES ) ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( _( "No" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDNO ) ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( _( "Cancel" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); - gtk_widget_show( w ); - ret = IDCANCEL; - } - else /* if (mode == MB_YESNO) */ - { - w = gtk_button_new_with_label( _( "Yes" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDYES ) ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( _( "No" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDNO ) ); - gtk_widget_show( w ); - ret = IDNO; - } - - if ( URL ) { - w = gtk_button_new_with_label( _( "Go to URL" ) ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", - GTK_SIGNAL_FUNC( dialog_url_callback ), NULL ); - g_object_set_data( G_OBJECT( w ), "URL", (void *)URL ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - } - - - gtk_widget_show( window ); - gtk_grab_add( window ); - - while ( loop ) - gtk_main_iteration(); - - gtk_grab_remove( window ); - gtk_widget_destroy( window ); - - return ret; +GtkToggleButton* toolbar_append_toggle_button( GtkToolbar* toolbar, const char* description, const char* icon, const char* commandName ){ + return toolbar_append_toggle_button( toolbar, description, icon, GlobalToggles_find( commandName ) ); } // ============================================================================= // File dialog -// fenris #3078 WHENHELLISFROZENOVER - -static void file_sel_callback( GtkWidget *widget, gpointer data ){ - GtkWidget *parent; - int *loop; - bool *success; - - parent = gtk_widget_get_toplevel( widget ); - loop = (int*)g_object_get_data( G_OBJECT( parent ), "loop" ); - success = (bool*)g_object_get_data( G_OBJECT( parent ), "success" ); - - if ( GPOINTER_TO_INT( data ) == IDOK ) { - *success = true; - } - - *loop = 0; -} - -#ifdef _WIN32 -#include -static OPENFILENAME ofn; /* common dialog box structure */ -static char szDirName[MAX_PATH]; /* directory string */ -static char szFile[MAX_PATH]; /* filename string */ -static char szFileTitle[MAX_PATH]; /* file title string */ -static int i, cbString; /* integer count variables */ -static HANDLE hf; /* file handle */ -#else -static char szFile[QER_MAX_NAMELEN]; -#endif - -#define FILEDLG_CUSTOM_FILTER_LENGTH 64 -// to be used with the advanced file selector - -class CFileType : public IFileTypeList -{ -struct filetype_copy_t -{ - void operator=( const filetype_t& other ){ - m_name = other.name; - m_pattern = other.pattern; - } - string_t m_name; - string_t m_pattern; -}; -public: -CFileType(){ - m_nTypes = 0; - m_pTypes = NULL; - m_strWin32Filters = NULL; - m_pstrGTKMasks = NULL; -} - -virtual ~CFileType(){ - delete[] m_pTypes; - DestroyWin32Filters(); - DestroyGTKMasks(); -} - -void addType( filetype_t type ){ - filetype_copy_t* newTypes = new filetype_copy_t [m_nTypes + 1]; - if ( m_nTypes > 0 ) { - for ( int i = 0; i < m_nTypes; i++ ) - newTypes[i] = m_pTypes[i]; - delete[] m_pTypes; - } - m_pTypes = newTypes; - m_pTypes[m_nTypes] = type; - m_nTypes++; - ConstructGTKMasks(); - ConstructWin32Filters(); -} - -filetype_t GetTypeForWin32Filter( const char *filter ) const { - for ( int i = 0; i < m_nTypes; i++ ) - if ( strcmp( m_pTypes[i].m_pattern.c_str(), filter ) == 0 ) { - return filetype_t( m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str() ); - } - return filetype_t(); -} - -filetype_t GetTypeForGTKMask( const char *mask ) const { - for ( int i = 0; i < m_nTypes; i++ ) - if ( strcmp( m_pstrGTKMasks[i],mask ) == 0 ) { - return filetype_t( m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str() ); - } - return filetype_t(); -} - -int GetNumTypes(){ - return m_nTypes; -} - -filetype_t GetTypeForIndex( int index ) const // Zero-based index. -{ - if ( index >= 0 && index < m_nTypes ) { - return filetype_t( m_pTypes[index].m_name.c_str(), m_pTypes[index].m_pattern.c_str() ); - } - return filetype_t(); -} - -char *m_strWin32Filters; -char **m_pstrGTKMasks; -private: -int m_nTypes; -filetype_copy_t *m_pTypes; - -void DestroyWin32Filters(){ - delete[] m_strWin32Filters; -} - -void ConstructWin32Filters(){ - const char *r; - char *w; - int i; - int len = 0; - DestroyWin32Filters(); - for ( i = 0; i < m_nTypes; i++ ) - len = len + strlen( m_pTypes[i].m_name.c_str() ) + strlen( m_pTypes[i].m_pattern.c_str() ) * 2 + 5; - m_strWin32Filters = new char[len + 1]; // length + null char - for ( i = 0, w = m_strWin32Filters; i < m_nTypes; i++ ) - { - for ( r = m_pTypes[i].m_name.c_str(); *r != '\0'; r++, w++ ) - *w = *r; - *w++ = ' '; - *w++ = '('; - for ( r = m_pTypes[i].m_pattern.c_str(); *r != '\0'; r++, w++ ) - *w = *r; - *w++ = ')'; - *w++ = '\0'; - for ( r = m_pTypes[i].m_pattern.c_str(); *r != '\0'; r++, w++ ) - *w = ( *r == ',' ) ? ';' : *r; - *w++ = '\0'; - } - m_strWin32Filters[len] = '\0'; -} - -void DestroyGTKMasks(){ - if ( m_pstrGTKMasks != NULL ) { - for ( char **p = m_pstrGTKMasks; *p != NULL; p++ ) - delete[] *p; - } - delete[] m_pstrGTKMasks; -} - -void ConstructGTKMasks(){ - const char *r; - char *w; - int i; - int len = 0; - DestroyGTKMasks(); - m_pstrGTKMasks = new char*[m_nTypes + 1]; - for ( i = 0; i < m_nTypes; i++ ) - { - len = strlen( m_pTypes[i].m_name.c_str() ) + strlen( m_pTypes[i].m_pattern.c_str() ) + 3; - m_pstrGTKMasks[i] = new char[len + 1]; // length + null char - w = m_pstrGTKMasks[i]; - for ( r = m_pTypes[i].m_name.c_str(); *r != '\0'; r++, w++ ) - *w = *r; - *w++ = ' '; - *w++ = '('; - for ( r = m_pTypes[i].m_pattern.c_str(); *r != '\0'; r++, w++ ) - *w = *r; - *w++ = ')'; - *w++ = '\0'; - } - m_pstrGTKMasks[m_nTypes] = NULL; -} - -}; - -#ifdef _WIN32 - -typedef struct { - gboolean open; - OPENFILENAME *ofn; - BOOL dlgRtnVal; - bool done; -} win32_native_file_dialog_comms_t; - -DWORD WINAPI win32_native_file_dialog_thread_func( LPVOID lpParam ){ - win32_native_file_dialog_comms_t *fileDialogComms; - fileDialogComms = (win32_native_file_dialog_comms_t *) lpParam; - if ( fileDialogComms->open ) { - fileDialogComms->dlgRtnVal = GetOpenFileName( fileDialogComms->ofn ); - } - else { - fileDialogComms->dlgRtnVal = GetSaveFileName( fileDialogComms->ofn ); - } - fileDialogComms->done = true; // No need to synchronize around lock, one-way gate. - return 0; -} - -#endif - -/** - * @param[in] baseSubDir should have a trailing slash if not @c NULL - */ -const char* file_dialog( void *parent, gboolean open, const char* title, const char* path, const char* pattern, const char *baseSubDir ){ - -#ifdef _WIN32 - static bool in_file_dialog = false; - HANDLE fileDialogThreadHandle; - win32_native_file_dialog_comms_t fileDialogComms; - bool dialogDone; -#endif - - // Gtk dialog - GtkWidget* file_sel; - char *new_path = NULL; - - const char* r; - char *v, *w; - filetype_t type; - CFileType typelist; - if ( pattern != NULL ) { - GetFileTypeRegistry()->getTypeList( pattern, &typelist ); - } - -#ifdef _WIN32 - if ( g_PrefsDlg.m_bNativeGUI ) { - // do that the native way - - if ( in_file_dialog ) { - return NULL; // Avoid recursive entry. - } - in_file_dialog = true; - /* Set the members of the OPENFILENAME structure. */ - // See http://msdn.microsoft.com/en-us/library/ms646839%28v=vs.85%29.aspx . - memset( &ofn, 0, sizeof( ofn ) ); - ofn.lStructSize = sizeof( ofn ); - ofn.hwndOwner = (HWND)GDK_WINDOW_HWND( g_pParentWnd->m_pWidget->window ); - ofn.nFilterIndex = 1; // The index is 1-based, not 0-based. This basically says, - // "select the first filter as default". - if ( pattern ) { - ofn.lpstrFilter = typelist.m_strWin32Filters; - } - else - { - // TODO: Would be a bit cleaner if we could extract this string from - // GetFileTypeRegistry() instead of hardcoding it here. - ofn.lpstrFilter = "all files\0*.*\0"; // Second '\0' will be added to end of string. - } - szFile[0] = '\0'; - ofn.lpstrFile = szFile; - ofn.nMaxFile = sizeof( szFile ); - if ( path ) { - // szDirName: Radiant uses unix convention for paths internally - // Win32 (of course) and Gtk (who would have thought) expect the '\\' convention - // copy path, replacing dir separators as appropriate - for ( r = path, w = szDirName; *r != '\0'; r++ ) - *w++ = ( *r == '/' ) ? '\\' : *r; - // terminate string - *w = '\0'; - ofn.lpstrInitialDir = szDirName; - } - ofn.lpstrTitle = title; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - memset( &fileDialogComms, 0, sizeof( fileDialogComms ) ); - fileDialogComms.open = open; - fileDialogComms.ofn = &ofn; - - fileDialogThreadHandle = - CreateThread( NULL, // lpThreadAttributes - 0, // dwStackSize, default stack size - win32_native_file_dialog_thread_func, // lpStartAddress, funcion to call - &fileDialogComms, // lpParameter, argument to pass to function - 0, // dwCreationFlags - NULL ); // lpThreadId - - dialogDone = false; - while ( 1 ) { - // Avoid blocking indefinitely. Another thread will set fileDialogComms->done to true; - // we don't want to be in an indefinite blocked state when this happens. We want to break - // out of here eventually. - while ( gtk_events_pending() ) { - gtk_main_iteration(); - } - if ( dialogDone ) { - break; - } - if ( fileDialogComms.done ) { - dialogDone = true; // One more loop of gtk_main_iteration() to get things in sync. - } - // Avoid tight infinte loop, add a small amount of sleep. - Sleep( 10 ); - } - // Make absolutely sure that the thread is finished before we call CloseHandle(). - WaitForSingleObject( fileDialogThreadHandle, INFINITE ); - CloseHandle( fileDialogThreadHandle ); - - in_file_dialog = false; - - if ( !fileDialogComms.dlgRtnVal ) { - return NULL; // Cancelled. - } - - if ( pattern != NULL ) { - type = typelist.GetTypeForIndex( ofn.nFilterIndex - 1 ); - } - - } - else - { -#endif - char buf[PATH_MAX]; - // do that the Gtk way - if ( title == NULL ) { - title = open ? _( "Open File" ) : _( "Save File" ); - } - - // we expect an actual path below, if the path is NULL we might crash - if ( !path || path[0] == '\0' ) { - strcpy( buf, g_pGameDescription->mEnginePath.GetBuffer() ); - strcat( buf, g_pGameDescription->mBaseGame.GetBuffer() ); - strcat( buf, "/" ); - if ( baseSubDir ) { - strcat( buf, baseSubDir ); - } - path = buf; - } - - // alloc new path with extra char for dir separator - new_path = new char[strlen( path ) + 1 + 1]; - // copy path, replacing dir separators as appropriate - for ( r = path, w = new_path; *r != '\0'; r++ ) - *w++ = ( *r == '/' ) ? G_DIR_SEPARATOR : *r; - // add dir separator to end of path if required - if ( *( w - 1 ) != G_DIR_SEPARATOR ) { - *w++ = G_DIR_SEPARATOR; - } - // terminate string - *w = '\0'; - - file_sel = gtk_file_chooser_dialog_new( title, - GTK_WINDOW( parent ), - open ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - open ? GTK_STOCK_OPEN : GTK_STOCK_SAVE, - GTK_RESPONSE_ACCEPT, - NULL ); - gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( file_sel ), new_path ); - delete[] new_path; - - // Setting the file chooser dialog to modal and centering it on the parent is done automatically. - - if ( pattern != NULL ) { - for ( int i = 0; i < typelist.GetNumTypes(); i++ ) { - GtkFileFilter *filter = gtk_file_filter_new(); - type = typelist.GetTypeForIndex( i ); - // We can use type.name here, or m_pstrGTKMasks[i], which includes the actual pattern. - gtk_file_filter_set_name( filter, typelist.m_pstrGTKMasks[i] ); - gtk_file_filter_add_pattern( filter, type.pattern ); - // "Note that the chooser takes ownership of the filter, so - // you have to ref and sink it if you want to keep a reference." - // So I guess we won't need to garbage collect this. - gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( file_sel ), filter ); - } - } - - if ( gtk_dialog_run( GTK_DIALOG( file_sel ) ) == GTK_RESPONSE_ACCEPT ) { - strcpy( szFile, gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( file_sel ) ) ); - } - else { - szFile[0] = '\0'; - } - - if ( pattern != NULL ) { - GtkFileFilter *filter = gtk_file_chooser_get_filter( GTK_FILE_CHOOSER( file_sel ) ); - if ( filter == NULL ) { - type = filetype_t(); - } - else { - type = typelist.GetTypeForGTKMask( gtk_file_filter_get_name( filter ) ); - } - } - gtk_widget_destroy( file_sel ); - -#ifdef _WIN32 -} -#endif - - // don't return an empty filename - if ( szFile[0] == '\0' ) { - return NULL; - } - - // convert back to unix format - for ( w = szFile; *w != '\0'; w++ ) - if ( *w == '\\' ) { - *w = '/'; - } - - /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */ - if ( !open && pattern != NULL ) { - v = strrchr( szFile, '/' ); - w = strrchr( szFile, '.' ); - if ( ( v && w && w < v ) || // Last '.' is before the file. - w == NULL ) { // Extension missing. - if ( type.pattern[0] ) { - w = szFile + strlen( szFile ); - strcpy( w, type.pattern + 1 ); // Add extension of selected filter type. - } - else { - // type will be empty if for example there were no filters for pattern, - // or if some other UI inconsistencies happen. - if ( gtk_MessageBox( parent, "No file extension specified in file to be saved.\nAttempt to save anyways?", - "GtkRadiant", MB_YESNO ) == IDNO ) { - return NULL; - } - } - } - else { // An extension was explicitly in the filename. - bool knownExtension = false; - for ( int i = typelist.GetNumTypes() - 1; i >= 0; i-- ) { - type = typelist.GetTypeForIndex( i ); - if ( type.pattern[0] && strcmp( w, type.pattern + 1 ) == 0 ) { - knownExtension = true; - break; - } - } - if ( !knownExtension ) { - if ( gtk_MessageBox( parent, "Unknown file extension for this save operation.\nAttempt to save anyways?", - "GtkRadiant", MB_YESNO ) == IDNO ) { - return NULL; - } - } - } - } - - // prompt to overwrite existing files - if ( !open ) { - if ( access( szFile, R_OK ) == 0 ) { - if ( gtk_MessageBox( parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO ) == IDNO ) { - return NULL; - } - } - } - - return szFile; -} - -char* WINAPI dir_dialog( void *parent, const char* title, const char* path ){ - GtkWidget* file_sel; - char* filename = (char*)NULL; - int loop = 1; - bool success = false; - - file_sel = gtk_file_selection_new( title ); - gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( file_sel )->ok_button ), "clicked", - GTK_SIGNAL_FUNC( file_sel_callback ), GINT_TO_POINTER( IDOK ) ); - gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( file_sel )->cancel_button ), "clicked", - GTK_SIGNAL_FUNC( file_sel_callback ), GINT_TO_POINTER( IDCANCEL ) ); - gtk_signal_connect( GTK_OBJECT( file_sel ), "delete_event", - GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); - gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION( file_sel ) ); - - if ( parent != NULL ) { - gtk_window_set_transient_for( GTK_WINDOW( file_sel ), GTK_WINDOW( parent ) ); - } - - gtk_widget_hide( GTK_FILE_SELECTION( file_sel )->file_list->parent ); - - g_object_set_data( G_OBJECT( file_sel ), "loop", &loop ); - g_object_set_data( G_OBJECT( file_sel ), "success", &success ); - - if ( path != NULL ) { - gtk_file_selection_set_filename( GTK_FILE_SELECTION( file_sel ), path ); - } - - gtk_grab_add( file_sel ); - gtk_widget_show( file_sel ); - - while ( loop ) - gtk_main_iteration(); - - filename = g_strdup( gtk_file_selection_get_filename( GTK_FILE_SELECTION( file_sel ) ) ); - - gtk_grab_remove( file_sel ); - gtk_widget_destroy( file_sel ); - - return filename; -} - -bool WINAPI color_dialog( void *parent, float *color, const char* title ){ +bool color_dialog( GtkWidget *parent, Vector3& color, const char* title ){ GtkWidget* dlg; double clr[3]; - int loop = 1, ret = IDCANCEL; + ModalDialog dialog; clr[0] = color[0]; clr[1] = color[1]; @@ -1484,97 +108,48 @@ bool WINAPI color_dialog( void *parent, float *color, const char* title ){ dlg = gtk_color_selection_dialog_new( title ); gtk_color_selection_set_color( GTK_COLOR_SELECTION( GTK_COLOR_SELECTION_DIALOG( dlg )->colorsel ), clr ); - gtk_signal_connect( GTK_OBJECT( dlg ), "delete_event", - GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); - gtk_signal_connect( GTK_OBJECT( dlg ), "destroy", - GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); - gtk_signal_connect( GTK_OBJECT( GTK_COLOR_SELECTION_DIALOG( dlg )->ok_button ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); - gtk_signal_connect( GTK_OBJECT( GTK_COLOR_SELECTION_DIALOG( dlg )->cancel_button ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); - g_object_set_data( G_OBJECT( dlg ), "loop", &loop ); - g_object_set_data( G_OBJECT( dlg ), "ret", &ret ); + g_signal_connect( G_OBJECT( dlg ), "delete_event", G_CALLBACK( dialog_delete_callback ), &dialog ); + g_signal_connect( G_OBJECT( GTK_COLOR_SELECTION_DIALOG( dlg )->ok_button ), "clicked", G_CALLBACK( dialog_button_ok ), &dialog ); + g_signal_connect( G_OBJECT( GTK_COLOR_SELECTION_DIALOG( dlg )->cancel_button ), "clicked", G_CALLBACK( dialog_button_cancel ), &dialog ); - if ( parent != NULL ) { + if ( parent != 0 ) { gtk_window_set_transient_for( GTK_WINDOW( dlg ), GTK_WINDOW( parent ) ); } - gtk_widget_show( dlg ); - gtk_grab_add( dlg ); - - while ( loop ) - gtk_main_iteration(); - - GdkColor gdkcolor; - gtk_color_selection_get_current_color( GTK_COLOR_SELECTION( GTK_COLOR_SELECTION_DIALOG( dlg )->colorsel ), &gdkcolor ); - clr[0] = gdkcolor.red / 65535.0; - clr[1] = gdkcolor.green / 65535.0; - clr[2] = gdkcolor.blue / 65535.0; - - gtk_grab_remove( dlg ); - gtk_widget_destroy( dlg ); + bool ok = modal_dialog_show( GTK_WINDOW( dlg ), dialog ) == eIDOK; + if ( ok ) { + GdkColor gdkcolor; + gtk_color_selection_get_current_color( GTK_COLOR_SELECTION( GTK_COLOR_SELECTION_DIALOG( dlg )->colorsel ), &gdkcolor ); + clr[0] = gdkcolor.red / 65535.0; + clr[1] = gdkcolor.green / 65535.0; + clr[2] = gdkcolor.blue / 65535.0; - if ( ret == IDOK ) { color[0] = (float)clr[0]; color[1] = (float)clr[1]; color[2] = (float)clr[2]; - - return true; } - return false; -} + gtk_widget_destroy( dlg ); -void OpenURL( const char *url ){ - // let's put a little comment - Sys_Printf( "OpenURL: %s\n", url ); -#ifdef __linux__ - // \todo FIXME: the way we open URLs on *nix should be improved. A script is good (see how I do on RTCW) - char command[2 * PATH_MAX]; - snprintf( command, sizeof( command ), "%s/openurl.sh \"%s\" &", g_strAppPath.GetBuffer(), url ); - if ( system( command ) != 0 ) { - gtk_MessageBox( g_pParentWnd->m_pWidget, "Failed to launch Netscape!" ); - } -#endif -#ifdef __APPLE__ - char command[2 * PATH_MAX]; - snprintf( command, sizeof( command ), - "open \"%s\" &", url, url ); - if ( system( command ) != 0 ) { - gtk_MessageBox( g_pParentWnd->m_pWidget, "Unable to launch browser!" ); - } -#endif -#ifdef _WIN32 - ShellExecute( (HWND)GDK_WINDOW_HWND( g_pParentWnd->m_pWidget->window ), "open", url, NULL, NULL, SW_SHOW ); -#endif + return ok; } -void CheckMenuSplitting( GtkWidget *&menu ){ - GtkWidget *item,*menu2; +void button_clicked_entry_browse_file( GtkWidget* widget, GtkEntry* entry ){ + const char *filename = file_dialog( gtk_widget_get_toplevel( widget ), TRUE, "Choose File", gtk_entry_get_text( entry ) ); - GtkRequisition requisition; - gint screen_height; - - gtk_widget_size_request( GTK_WIDGET( menu ), &requisition ); - screen_height = gdk_screen_height(); - - if ( ( screen_height - requisition.height ) < 20 ) { - menu2 = gtk_menu_new(); + if ( filename != 0 ) { + gtk_entry_set_text( entry, filename ); + } +} - // move the last 2 items to a submenu (3 because of win32) - for ( int i = 0; i < 3; i++ ) - { - item = GTK_WIDGET( g_list_last( gtk_container_children( GTK_CONTAINER( menu ) ) )->data ); - gtk_widget_ref( item ); - gtk_container_remove( GTK_CONTAINER( menu ), item ); - gtk_menu_append( GTK_MENU( menu2 ), item ); - gtk_widget_unref( item ); - } +void button_clicked_entry_browse_directory( GtkWidget* widget, GtkEntry* entry ){ + const char* text = gtk_entry_get_text( entry ); + char *dir = dir_dialog( gtk_widget_get_toplevel( widget ), "Choose Directory", path_is_absolute( text ) ? text : "" ); - item = gtk_menu_item_new_with_label( "--------" ); - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), menu2 ); - menu = menu2; + if ( dir != 0 ) { + gchar* converted = g_filename_to_utf8( dir, -1, 0, 0, 0 ); + gtk_entry_set_text( entry, converted ); + g_free( dir ); + g_free( converted ); } }