]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/build.cpp
radiant: replace StringBuffer with std::string
[xonotic/netradiant.git] / radiant / build.cpp
index 1a4149882e12b739e44e89804dab4518cffb1f38..4e5ca1863a75fa86136835ac37b444be2c26b941 100644 (file)
@@ -22,6 +22,7 @@
 #include "build.h"
 #include "debugging/debugging.h"
 
+#include <gtk/gtk.h>
 #include <map>
 #include <list>
 #include "stream/stringstream.h"
@@ -40,12 +41,12 @@ void build_set_variable( const char* name, const char* value ){
        g_build_variables[name] = value;
 }
 
-const char* build_get_variable( const char* name ){
-       Variables::iterator i = g_build_variables.find( name );
+const char* build_get_variable( const std::string& name ){
+       Variables::iterator i = g_build_variables.find( name.c_str() );
        if ( i != g_build_variables.end() ) {
                return ( *i ).second.c_str();
        }
-       globalErrorStream() << "undefined build variable: " << makeQuoted( name ) << "\n";
+       globalErrorStream() << "undefined build variable: " << makeQuoted( name.c_str() ) << "\n";
        return "";
 }
 
@@ -55,55 +56,81 @@ const char* build_get_variable( const char* name ){
 class Evaluatable
 {
 public:
-virtual void evaluate( StringBuffer& output ) = 0;
+virtual ~Evaluatable() = default;
+virtual std::string evaluate() = 0;
 virtual void exportXML( XMLImporter& importer ) = 0;
 };
 
 class VariableString : public Evaluatable
 {
-CopiedString m_string;
+std::string m_string;
 public:
 VariableString() : m_string(){
 }
-VariableString( const char* string ) : m_string( string ){
+VariableString( std::string string ) : m_string( std::move(string) ){
 }
 const char* c_str() const {
        return m_string.c_str();
 }
-void setString( const char* string ){
+void setString( const std::string& string ){
        m_string = string;
 }
-void evaluate( StringBuffer& output ){
-       StringBuffer variable;
+std::string evaluate(){
+       // replace ".[ExecutableType]" with "[ExecutableExt]"
+       {
+               size_t pos;
+               const std::string pattern = ".[ExecutableType]";
+               while ( ( pos = m_string.find(pattern) ) != std::string::npos ) {
+                       m_string.replace(pos, pattern.length(), "[ExecutableExt]");
+               }
+       }
+
+       // add missing [ExtraQ3map2Args] if "[RadiantPath]q3map2[ExecutableExt]"
+       {
+               size_t pos;
+               const std::string pattern = "\"[RadiantPath]q3map2[ExecutableExt]\"";
+               const std::string extra = "[ExtraQ3map2Args]";
+               if ( ( pos = m_string.find(pattern) ) != std::string::npos
+                               && m_string.find(extra) == std::string::npos )
+               {
+                       m_string.insert(pos + pattern.size(), " ");
+                       m_string.insert(pos + pattern.size() + 1, extra);
+               }
+       }
+
+       std::string output;
+       std::string variable_name;
        bool in_variable = false;
-       for ( const char* i = m_string.c_str(); *i != '\0'; ++i )
+       for ( const char c : m_string )
        {
                if ( !in_variable ) {
-                       switch ( *i )
+                       switch ( c )
                        {
                        case '[':
                                in_variable = true;
                                break;
                        default:
-                               output.push_back( *i );
+                               output += c;
                                break;
                        }
                }
                else
                {
-                       switch ( *i )
+                       switch ( c )
                        {
                        case ']':
                                in_variable = false;
-                               output.push_string( build_get_variable( variable.c_str() ) );
-                               variable.clear();
+                               output += build_get_variable( variable_name );
+                               variable_name.clear();
                                break;
                        default:
-                               variable.push_back( *i );
+                               variable_name += c;
                                break;
                        }
                }
        }
+
+       return output;
 }
 void exportXML( XMLImporter& importer ){
        importer << c_str();
@@ -121,12 +148,12 @@ Conditional( VariableString* test ) : m_test( test ){
        delete m_test;
        delete m_result;
 }
-void evaluate( StringBuffer& output ){
-       StringBuffer buffer;
-       m_test->evaluate( buffer );
-       if ( !string_empty( buffer.c_str() ) ) {
-               m_result->evaluate( output );
+std::string evaluate(){
+       std::string result = m_test->evaluate();
+       if ( result.empty() ) {
+               return result;
        }
+       return m_result->evaluate();
 }
 void exportXML( XMLImporter& importer ){
        StaticElement conditionElement( "cond" );
@@ -152,11 +179,13 @@ public:
 void push_back( Evaluatable* evaluatable ){
        m_evaluatables.push_back( evaluatable );
 }
-void evaluate( StringBuffer& output ){
+std::string evaluate(){
+       std::string result;
        for ( Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i )
        {
-               ( *i )->evaluate( output );
+               result += ( *i )->evaluate();
        }
+       return result;
 }
 void exportXML( XMLImporter& importer ){
        for ( Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i )
@@ -171,22 +200,23 @@ void exportXML( XMLImporter& importer ){
 class XMLElementParser : public TextOutputStream
 {
 public:
+virtual ~XMLElementParser() = default;
 virtual XMLElementParser& pushElement( const XMLElement& element ) = 0;
 virtual void popElement( const char* name ) = 0;
 };
 
 class VariableStringXMLConstructor : public XMLElementParser
 {
-StringBuffer m_buffer;
+std::string m_buffer;
 VariableString& m_variableString;
 public:
 VariableStringXMLConstructor( VariableString& variableString ) : m_variableString( variableString ){
 }
 ~VariableStringXMLConstructor(){
-       m_variableString.setString( m_buffer.c_str() );
+       m_variableString.setString( std::move(m_buffer) );
 }
 std::size_t write( const char* buffer, std::size_t length ){
-       m_buffer.push_range( buffer, buffer + length );
+       m_buffer.append( buffer, length );
        return length;
 }
 XMLElementParser& pushElement( const XMLElement& element ){
@@ -199,16 +229,16 @@ void popElement( const char* name ){
 
 class ConditionalXMLConstructor : public XMLElementParser
 {
-StringBuffer m_buffer;
+std::string m_buffer;
 Conditional& m_conditional;
 public:
 ConditionalXMLConstructor( Conditional& conditional ) : m_conditional( conditional ){
 }
 ~ConditionalXMLConstructor(){
-       m_conditional.m_result = new VariableString( m_buffer.c_str() );
+       m_conditional.m_result = new VariableString( std::move( m_buffer ) );
 }
 std::size_t write( const char* buffer, std::size_t length ){
-       m_buffer.push_range( buffer, buffer + length );
+       m_buffer.append( buffer, length );
        return length;
 }
 XMLElementParser& pushElement( const XMLElement& element ){
@@ -221,7 +251,7 @@ void popElement( const char* name ){
 
 class ToolXMLConstructor : public XMLElementParser
 {
-StringBuffer m_buffer;
+std::string m_buffer;
 Tool& m_tool;
 ConditionalXMLConstructor* m_conditional;
 public:
@@ -231,7 +261,7 @@ ToolXMLConstructor( Tool& tool ) : m_tool( tool ){
        flush();
 }
 std::size_t write( const char* buffer, std::size_t length ){
-       m_buffer.push_range( buffer, buffer + length );
+       m_buffer.append( buffer, length );
        return length;
 }
 XMLElementParser& pushElement( const XMLElement& element ){
@@ -256,7 +286,7 @@ void popElement( const char* name ){
 
 void flush(){
        if ( !m_buffer.empty() ) {
-               m_tool.push_back( new VariableString( m_buffer.c_str() ) );
+               m_tool.push_back( new VariableString( std::move( m_buffer ) ) );
                m_buffer.clear();
        }
 }
@@ -293,7 +323,7 @@ void popElement( const char* name ){
 };
 
 typedef std::pair<CopiedString, Build> BuildPair;
-#define SEPARATOR_STRING "-"
+const char *SEPARATOR_STRING = "-";
 static bool is_separator( const BuildPair &p ){
        if ( !string_equal( p.first.c_str(), SEPARATOR_STRING ) ) {
                return false;
@@ -308,21 +338,12 @@ static bool is_separator( const BuildPair &p ){
 }
 
 
-class BuildPairEqual
-{
-const char* m_name;
-public:
-BuildPairEqual( const char* name ) : m_name( name ){
-}
-bool operator()( const BuildPair& self ) const {
-       return string_equal( self.first.c_str(), m_name );
-}
-};
-
 typedef std::list<BuildPair> Project;
 
 Project::iterator Project_find( Project& project, const char* name ){
-       return std::find_if( project.begin(), project.end(), BuildPairEqual( name ) );
+       return std::find_if(project.begin(), project.end(), [&](const BuildPair &self) {
+               return string_equal(self.first.c_str(), name);
+       });
 }
 
 Project::iterator Project_find( Project& project, std::size_t index ){
@@ -480,8 +501,7 @@ void project_verify( Project& project, Tools& tools ){
 void build_run( const char* name, CommandListener& listener ){
        for ( Tools::iterator i = g_build_tools.begin(); i != g_build_tools.end(); ++i )
        {
-               StringBuffer output;
-               ( *i ).second.evaluate( output );
+               std::string output = ( *i ).second.evaluate();
                build_set_variable( ( *i ).first.c_str(), output.c_str() );
        }
 
@@ -491,8 +511,7 @@ void build_run( const char* name, CommandListener& listener ){
                        Build& build = ( *i ).second;
                        for ( Build::iterator j = build.begin(); j != build.end(); ++j )
                        {
-                               StringBuffer output;
-                               ( *j ).evaluate( output );
+                               std::string output = ( *j ).evaluate();
                                listener.execute( output.c_str() );
                        }
                }
@@ -633,51 +652,45 @@ void build_commands_write( const char* filename ){
 
 
 #include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
 
 #include "gtkutil/dialog.h"
 #include "gtkutil/closure.h"
 #include "gtkutil/window.h"
 #include "gtkdlgs.h"
 
-void Build_refreshMenu( GtkMenu* menu );
+void Build_refreshMenu( ui::Menu menu );
 
 
-void BSPCommandList_Construct( GtkListStore* store, Project& project ){
-       gtk_list_store_clear( store );
+void BSPCommandList_Construct( ui::ListStore store, Project& project ){
+       store.clear();
 
        for ( Project::iterator i = project.begin(); i != project.end(); ++i )
        {
-               const char* buildName = ( *i ).first.c_str();
-
-               GtkTreeIter buildIter;
-               gtk_list_store_append( store, &buildIter );
-               gtk_list_store_set( store, &buildIter, 0, const_cast<char*>( buildName ), -1 );
+               store.append(0, (*i).first.c_str());
        }
 
-       GtkTreeIter lastIter;
-       gtk_list_store_append( store, &lastIter );
+       store.append();
 }
 
 class ProjectList
 {
 public:
 Project& m_project;
-GtkListStore* m_store;
+ui::ListStore m_store{ui::null};
 bool m_changed;
 ProjectList( Project& project ) : m_project( project ), m_changed( false ){
 }
 };
 
-gboolean project_cell_edited( GtkCellRendererText* cell, gchar* path_string, gchar* new_text, ProjectList* projectList ){
+gboolean project_cell_edited(ui::CellRendererText cell, gchar* path_string, gchar* new_text, ProjectList* projectList ){
        Project& project = projectList->m_project;
 
-       GtkTreePath* path = ui::TreePath( path_string );
+       auto path = ui::TreePath( path_string );
 
        ASSERT_MESSAGE( gtk_tree_path_get_depth( path ) == 1, "invalid path length" );
 
        GtkTreeIter iter;
-       gtk_tree_model_get_iter( GTK_TREE_MODEL( projectList->m_store ), &iter, path );
+       gtk_tree_model_get_iter(projectList->m_store, &iter, path );
 
        Project::iterator i = Project_find( project, gtk_tree_path_get_indices( path )[0] );
        if ( i != project.end() ) {
@@ -697,8 +710,7 @@ gboolean project_cell_edited( GtkCellRendererText* cell, gchar* path_string, gch
                project.push_back( Project::value_type( new_text, Build() ) );
 
                gtk_list_store_set( projectList->m_store, &iter, 0, new_text, -1 );
-               GtkTreeIter lastIter;
-               gtk_list_store_append( projectList->m_store, &lastIter );
+               projectList->m_store.append();
        }
 
        gtk_tree_path_free( path );
@@ -708,15 +720,15 @@ gboolean project_cell_edited( GtkCellRendererText* cell, gchar* path_string, gch
        return FALSE;
 }
 
-gboolean project_key_press( ui::Widget widget, GdkEventKey* event, ProjectList* projectList ){
+gboolean project_key_press( ui::TreeView widget, GdkEventKey* event, ProjectList* projectList ){
        Project& project = projectList->m_project;
 
-       if ( event->keyval == GDK_Delete ) {
-               GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( widget ) );
+       if ( event->keyval == GDK_KEY_Delete ) {
+               auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(widget));
                GtkTreeIter iter;
                GtkTreeModel* model;
                if ( gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
-                       GtkTreePath* path = gtk_tree_model_get_path( model, &iter );
+                       auto path = gtk_tree_model_get_path( model, &iter );
                        Project::iterator x = Project_find( project, gtk_tree_path_get_indices( path )[0] );
                        gtk_tree_path_free( path );
 
@@ -735,15 +747,15 @@ gboolean project_key_press( ui::Widget widget, GdkEventKey* event, ProjectList*
 
 Build* g_current_build = 0;
 
-gboolean project_selection_changed( GtkTreeSelection* selection, GtkListStore* store ){
+gboolean project_selection_changed( ui::TreeSelection selection, ui::ListStore store ){
        Project& project = g_build_project;
 
-       gtk_list_store_clear( store );
+       store.clear();
 
        GtkTreeIter iter;
        GtkTreeModel* model;
        if ( gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
-               GtkTreePath* path = gtk_tree_model_get_path( model, &iter );
+               auto path = gtk_tree_model_get_path( model, &iter );
                Project::iterator x = Project_find( project, gtk_tree_path_get_indices( path )[0] );
                gtk_tree_path_free( path );
 
@@ -753,12 +765,9 @@ gboolean project_selection_changed( GtkTreeSelection* selection, GtkListStore* s
 
                        for ( Build::iterator i = build.begin(); i != build.end(); ++i )
                        {
-                               GtkTreeIter commandIter;
-                               gtk_list_store_append( store, &commandIter );
-                               gtk_list_store_set( store, &commandIter, 0, const_cast<char*>( ( *i ).c_str() ), -1 );
+                               store.append(0, (*i).c_str());
                        }
-                       GtkTreeIter lastIter;
-                       gtk_list_store_append( store, &lastIter );
+                       store.append();
                }
                else
                {
@@ -773,18 +782,18 @@ gboolean project_selection_changed( GtkTreeSelection* selection, GtkListStore* s
        return FALSE;
 }
 
-gboolean commands_cell_edited( GtkCellRendererText* cell, gchar* path_string, gchar* new_text, GtkListStore* store ){
+gboolean commands_cell_edited(ui::CellRendererText cell, const gchar* path_string, const gchar* new_text, ui::ListStore store ){
        if ( g_current_build == 0 ) {
                return FALSE;
        }
        Build& build = *g_current_build;
 
-       GtkTreePath* path = ui::TreePath( path_string );
+       auto path = ui::TreePath( path_string );
 
        ASSERT_MESSAGE( gtk_tree_path_get_depth( path ) == 1, "invalid path length" );
 
        GtkTreeIter iter;
-       gtk_tree_model_get_iter( GTK_TREE_MODEL( store ), &iter, path );
+       gtk_tree_model_get_iter(store, &iter, path );
 
        Build::iterator i = Build_find( build, gtk_tree_path_get_indices( path )[0] );
        if ( i != build.end() ) {
@@ -799,8 +808,7 @@ gboolean commands_cell_edited( GtkCellRendererText* cell, gchar* path_string, gc
 
                gtk_list_store_set( store, &iter, 0, new_text, -1 );
 
-               GtkTreeIter lastIter;
-               gtk_list_store_append( store, &lastIter );
+               store.append();
        }
 
        gtk_tree_path_free( path );
@@ -810,18 +818,18 @@ gboolean commands_cell_edited( GtkCellRendererText* cell, gchar* path_string, gc
        return FALSE;
 }
 
-gboolean commands_key_press( ui::Widget widget, GdkEventKey* event, GtkListStore* store ){
+gboolean commands_key_press( ui::TreeView widget, GdkEventKey* event, ui::ListStore store ){
        if ( g_current_build == 0 ) {
                return FALSE;
        }
        Build& build = *g_current_build;
 
-       if ( event->keyval == GDK_Delete ) {
-               GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( widget ) );
+       if ( event->keyval == GDK_KEY_Delete ) {
+               auto selection = gtk_tree_view_get_selection(widget );
                GtkTreeIter iter;
                GtkTreeModel* model;
                if ( gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
-                       GtkTreePath* path = gtk_tree_model_get_path( model, &iter );
+                       auto path = gtk_tree_model_get_path( model, &iter );
                        Build::iterator i = Build_find( build, gtk_tree_path_get_indices( path )[0] );
                        gtk_tree_path_free( path );
 
@@ -840,96 +848,95 @@ gboolean commands_key_press( ui::Widget widget, GdkEventKey* event, GtkListStore
 ui::Window BuildMenuDialog_construct( ModalDialog& modal, ProjectList& projectList ){
        ui::Window window = MainFrame_getWindow().create_dialog_window("Build Menu", G_CALLBACK(dialog_delete_callback ), &modal, -1, 400 );
 
-       ui::Widget buildView;
+       // FIXME: GTK_WIN_POS_CENTER_ON_PARENT must be used instead but does not work
+       // for unknown reason.
+       // It's possible MaingFrame_getWindow() does not return the main window.
+       // It's known the preferences window has same issue when using MaingFrame_getWindow().
+       gtk_window_set_position( window, GTK_WIN_POS_CENTER_ALWAYS );
 
        {
-               GtkTable* table1 = create_dialog_table( 2, 2, 4, 4, 4 );
-               gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( table1 ) );
+               auto table1 = create_dialog_table( 2, 2, 4, 4, 4 );
+               window.add(table1);
                {
-                       GtkVBox* vbox = create_dialog_vbox( 4 );
-                       gtk_table_attach( table1, GTK_WIDGET( vbox ), 1, 2, 0, 1,
-                                                         (GtkAttachOptions) ( GTK_FILL ),
-                                                         (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
+                       auto vbox = create_dialog_vbox( 4 );
+            table1.attach(vbox, {1, 2, 0, 1}, {GTK_FILL, GTK_FILL});
                        {
-                               GtkButton* button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal );
-                               gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
+                               auto button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal );
+                               vbox.pack_start( button, FALSE, FALSE, 0 );
                        }
                        {
-                               GtkButton* button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal );
-                               gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 );
+                               auto button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal );
+                               vbox.pack_start( button, FALSE, FALSE, 0 );
                        }
                }
+               auto buildViewStore = ui::ListStore::from(gtk_list_store_new( 1, G_TYPE_STRING ));
+               auto buildView = ui::TreeView( ui::TreeModel::from( buildViewStore._handle ));
                {
-                       GtkFrame* frame = create_dialog_frame( "Build menu" );
-                       gtk_table_attach( table1, GTK_WIDGET( frame ), 0, 1, 0, 1,
-                                                         (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
-                                                         (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), 0, 0 );
+                       auto frame = create_dialog_frame( "Build menu" );
+            table1.attach(frame, {0, 1, 0, 1});
                        {
-                               GtkScrolledWindow* scr = create_scrolled_window( GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4 );
-                               gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( scr ) );
+                               auto scr = create_scrolled_window( ui::Policy::NEVER, ui::Policy::AUTOMATIC, 4 );
+                               frame.add(scr);
 
                                {
-                                       GtkListStore* store = gtk_list_store_new( 1, G_TYPE_STRING );
+                                       auto view = buildView;
+                                       auto store = buildViewStore;
+                                       gtk_tree_view_set_headers_visible(view, FALSE );
 
-                                       ui::Widget view = ui::TreeView( ui::TreeModel(GTK_TREE_MODEL( store ) ));
-                                       gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE );
-
-                                       auto renderer = ui::CellRendererText();
+                                       auto renderer = ui::CellRendererText(ui::New);
                                        object_set_boolean_property( G_OBJECT( renderer ), "editable", TRUE );
-                                       g_signal_connect( G_OBJECT(renderer), "edited", G_CALLBACK( project_cell_edited ), &projectList );
+                                       renderer.connect("edited", G_CALLBACK( project_cell_edited ), &projectList );
 
-                                       GtkTreeViewColumn* column = ui::TreeViewColumn( "", renderer, {{"text", 0}} );
-                                       gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
+                                       auto column = ui::TreeViewColumn( "", renderer, {{"text", 0}} );
+                                       gtk_tree_view_append_column(view, column );
 
-                                       GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
+                                       auto selection = gtk_tree_view_get_selection(view );
                                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE );
 
-                                       gtk_widget_show( view );
+                                       view.show();
 
-                                       buildView = view;
                                        projectList.m_store = store;
-                                       gtk_container_add( GTK_CONTAINER( scr ), view );
+                                       scr.add(view);
 
-                                       g_signal_connect( G_OBJECT( view ), "key_press_event", G_CALLBACK( project_key_press ), &projectList );
+                                       view.connect( "key_press_event", G_CALLBACK( project_key_press ), &projectList );
 
-                                       g_object_unref( G_OBJECT( store ) );
+                                       store.unref();
                                }
                        }
                }
                {
-                       GtkFrame* frame = create_dialog_frame( "Commandline" );
-                       gtk_table_attach( table1, GTK_WIDGET( frame ), 0, 1, 1, 2,
-                                                         (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
-                                                         (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), 0, 0 );
+                       auto frame = create_dialog_frame( "Command line" );
+            table1.attach(frame, {0, 1, 1, 2});
                        {
-                               GtkScrolledWindow* scr = create_scrolled_window( GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4 );
-                               gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( scr ) );
+                               auto scr = create_scrolled_window( ui::Policy::NEVER, ui::Policy::AUTOMATIC, 4 );
+                               frame.add(scr);
 
                                {
-                                       GtkListStore* store = gtk_list_store_new( 1, G_TYPE_STRING );
+                                       auto store = ui::ListStore::from(gtk_list_store_new( 1, G_TYPE_STRING ));
 
-                                       ui::Widget view = ui::TreeView(ui::TreeModel( GTK_TREE_MODEL( store ) ));
-                                       gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE );
+                                       auto view = ui::TreeView(ui::TreeModel::from( store._handle ));
+                                       gtk_tree_view_set_headers_visible(view, FALSE );
 
-                                       auto renderer = ui::CellRendererText();
+                                       auto renderer = ui::CellRendererText(ui::New);
                                        object_set_boolean_property( G_OBJECT( renderer ), "editable", TRUE );
-                                       g_signal_connect( G_OBJECT(renderer), "edited", G_CALLBACK( commands_cell_edited ), store );
+                                       renderer.connect( "edited", G_CALLBACK( commands_cell_edited ), store );
 
-                                       GtkTreeViewColumn* column = ui::TreeViewColumn( "", renderer, {{"text", 0}} );
-                                       gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
+                                       auto column = ui::TreeViewColumn( "", renderer, {{"text", 0}} );
+                                       gtk_tree_view_append_column(view, column );
 
-                                       GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
+                                       auto selection = gtk_tree_view_get_selection(view );
                                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE );
 
-                                       gtk_widget_show( view );
+                                       view.show();
 
-                                       gtk_container_add( GTK_CONTAINER( scr ), view );
+                                       scr.add(view);
 
-                                       g_object_unref( G_OBJECT( store ) );
+                                       store.unref();
 
-                                       g_signal_connect( G_OBJECT( view ), "key_press_event", G_CALLBACK( commands_key_press ), store );
+                                       view.connect( "key_press_event", G_CALLBACK( commands_key_press ), store );
 
-                                       g_signal_connect( G_OBJECT( gtk_tree_view_get_selection( GTK_TREE_VIEW( buildView ) ) ), "changed", G_CALLBACK( project_selection_changed ), store );
+                                       auto sel = ui::TreeSelection::from(gtk_tree_view_get_selection(buildView ));
+                                       sel.connect( "changed", G_CALLBACK( project_selection_changed ), store );
                                }
                        }
                }
@@ -964,7 +971,7 @@ void DoBuildMenu(){
                g_build_changed = true;
        }
 
-       gtk_widget_destroy( GTK_WIDGET( window ) );
+       window.destroy();
 }
 
 
@@ -974,32 +981,30 @@ void DoBuildMenu(){
 #include "preferences.h"
 #include "qe3.h"
 
-typedef struct _GtkMenuItem GtkMenuItem;
-
 class BuildMenuItem
 {
 const char* m_name;
 public:
-GtkMenuItem* m_item;
-BuildMenuItem( const char* name, GtkMenuItem* item )
+ui::MenuItem m_item;
+BuildMenuItem( const char* name, ui::MenuItem item )
        : m_name( name ), m_item( item ){
 }
 void run(){
        RunBSP( m_name );
 }
-typedef MemberCaller<BuildMenuItem, &BuildMenuItem::run> RunCaller;
+typedef MemberCaller<BuildMenuItem, void(), &BuildMenuItem::run> RunCaller;
 };
 
 typedef std::list<BuildMenuItem> BuildMenuItems;
 BuildMenuItems g_BuildMenuItems;
 
 
-GtkMenu* g_bsp_menu;
+ui::Menu g_bsp_menu{ui::null};
 
-void Build_constructMenu( GtkMenu* menu ){
+void Build_constructMenu( ui::Menu menu ){
        for ( Project::iterator i = g_build_project.begin(); i != g_build_project.end(); ++i )
        {
-               g_BuildMenuItems.push_back( BuildMenuItem( ( *i ).first.c_str(), 0 ) );
+               g_BuildMenuItems.push_back( BuildMenuItem( ( *i ).first.c_str(), ui::MenuItem(ui::null) ) );
                if ( is_separator( *i ) ) {
                        g_BuildMenuItems.back().m_item = menu_separator( menu );
                }
@@ -1011,10 +1016,10 @@ void Build_constructMenu( GtkMenu* menu ){
 }
 
 
-void Build_refreshMenu( GtkMenu* menu ){
-       for ( BuildMenuItems::iterator i = g_BuildMenuItems.begin(); i != g_BuildMenuItems.end(); ++i )
+void Build_refreshMenu( ui::Menu menu ){
+       for (auto i = g_BuildMenuItems.begin(); i != g_BuildMenuItems.end(); ++i )
        {
-               gtk_container_remove( GTK_CONTAINER( menu ), GTK_WIDGET( ( *i ).m_item ) );
+               menu.remove(ui::MenuItem(i->m_item));
        }
 
        g_BuildMenuItems.clear();
@@ -1052,7 +1057,7 @@ void SaveBuildMenu(){
 #include "stringio.h"
 
 void BuildMenu_Construct(){
-       GlobalPreferenceSystem().registerPreference( "BuildMenu", CopiedStringImportStringCaller( g_buildMenu ), CopiedStringExportStringCaller( g_buildMenu ) );
+       GlobalPreferenceSystem().registerPreference( "BuildMenu", make_property_string( g_buildMenu ) );
        LoadBuildMenu();
 }
 void BuildMenu_Destroy(){