rewrite GlobalShortcuts_foreach() to use functor semantics

This commit is contained in:
Garux 2020-03-09 23:06:45 +03:00
parent e25f67ca29
commit 64e2eebfb3
2 changed files with 78 additions and 109 deletions

View File

@ -36,27 +36,22 @@
struct ShortcutValue{
Accelerator accelerator;
const Accelerator accelerator_default;
int type; // isRegistered
int type; // 0 = !isRegistered, 1 = command, 2 = toggle
ShortcutValue( const Accelerator& a ) : accelerator( a ), accelerator_default( a ), type( 0 ){
}
};
typedef std::map<CopiedString, ShortcutValue> Shortcuts;
void Shortcuts_foreach( Shortcuts& shortcuts, CommandVisitor& visitor ){
for ( Shortcuts::iterator i = shortcuts.begin(); i != shortcuts.end(); ++i )
{
visitor.visit( ( *i ).first.c_str(), ( *i ).second.accelerator );
}
}
Shortcuts g_shortcuts;
const Accelerator& GlobalShortcuts_insert( const char* name, const Accelerator& accelerator ){
return ( *g_shortcuts.insert( Shortcuts::value_type( name, ShortcutValue( accelerator ) ) ).first ).second.accelerator;
}
void GlobalShortcuts_foreach( CommandVisitor& visitor ){
Shortcuts_foreach( g_shortcuts, visitor );
template<typename Functor>
void GlobalShortcuts_foreach( Functor& functor ){
for ( auto& pair : g_shortcuts )
functor( pair.first.c_str(), pair.second.accelerator );
}
void GlobalShortcuts_register( const char* name, int type ){
@ -67,12 +62,9 @@ void GlobalShortcuts_register( const char* name, int type ){
}
void GlobalShortcuts_reportUnregistered(){
for ( Shortcuts::iterator i = g_shortcuts.begin(); i != g_shortcuts.end(); ++i )
{
if ( ( *i ).second.accelerator.key != 0 && ( *i ).second.type == 0 ) {
globalWarningStream() << "shortcut not registered: " << ( *i ).first.c_str() << "\n";
}
}
for ( auto& pair : g_shortcuts )
if ( pair.second.accelerator.key != 0 && pair.second.type == 0 )
globalWarningStream() << "shortcut not registered: " << pair.first.c_str() << "\n";
}
typedef std::map<CopiedString, Command> Commands;
@ -258,6 +250,59 @@ gboolean accelerator_tree_butt_press( GtkWidget* widget, GdkEventButton* event,
return FALSE;
}
class VerifyAcceleratorNotTaken
{
const char *commandName;
const Accelerator &newAccel;
GtkWidget *widget;
GtkTreeModel *model;
public:
bool allow;
VerifyAcceleratorNotTaken( const char *name, const Accelerator &accelerator, GtkWidget *w, GtkTreeModel *m ) :
commandName( name ), newAccel( accelerator ), widget( w ), model( m ), allow( true ){
}
void operator()( const char* name, Accelerator& accelerator ){
if ( !allow
|| accelerator.key == 0
|| !strcmp( name, commandName ) ) {
return;
}
if ( accelerator == newAccel ) {
StringOutputStream msg;
msg << "The command " << name << " is already assigned to the key " << accelerator << ".\n\n"
<< "Do you want to unassign " << name << " first?";
EMessageBoxReturn r = gtk_MessageBox( widget, msg.c_str(), "Key already used", eMB_YESNOCANCEL );
if ( r == eIDYES ) {
// clear the ACTUAL accelerator too!
disconnect_accelerator( name );
// delete the modifier
accelerator = accelerator_null();
// empty the cell of the key binds dialog
GtkTreeIter i;
if ( gtk_tree_model_get_iter_first( GTK_TREE_MODEL( model ), &i ) ) {
for (;; )
{
GValue val;
memset( &val, 0, sizeof( val ) );
gtk_tree_model_get_value( GTK_TREE_MODEL( model ), &i, 0, &val );
const char *thisName = g_value_get_string( &val );;
if ( !strcmp( thisName, name ) ) {
gtk_list_store_set( GTK_LIST_STORE( model ), &i, 1, "", -1 );
}
g_value_unset( &val );
if ( !gtk_tree_model_iter_next( GTK_TREE_MODEL( model ), &i ) ) {
break;
}
}
}
}
else if ( r == eIDCANCEL ) {
// aborted
allow = false;
}
}
}
};
gboolean accelerator_window_key_press( GtkWidget *widget, GdkEventKey *event, gpointer dialogptr ){
command_list_dialog_t &dialog = *(command_list_dialog_t *) dialogptr;
@ -306,66 +351,10 @@ gboolean accelerator_window_key_press( GtkWidget *widget, GdkEventKey *event, gp
}
// 8. build an Accelerator
Accelerator newAccel( event->keyval, (GdkModifierType) event->state );
const Accelerator newAccel( accelerator_for_event_key( event ) );
// 8. verify the key is still free, show a dialog to ask what to do if not
class VerifyAcceleratorNotTaken : public CommandVisitor
{
const char *commandName;
const Accelerator &newAccel;
GtkWidget *widget;
GtkTreeModel *model;
public:
bool allow;
VerifyAcceleratorNotTaken( const char *name, const Accelerator &accelerator, GtkWidget *w, GtkTreeModel *m ) :
commandName( name ), newAccel( accelerator ), widget( w ), model( m ), allow( true ){
}
void visit( const char* name, Accelerator& accelerator ){
if ( !strcmp( name, commandName ) ) {
return;
}
if ( !allow ) {
return;
}
if ( accelerator.key == 0 ) {
return;
}
if ( accelerator == newAccel ) {
StringOutputStream msg;
msg << "The command " << name << " is already assigned to the key " << accelerator << ".\n\n"
<< "Do you want to unassign " << name << " first?";
EMessageBoxReturn r = gtk_MessageBox( widget, msg.c_str(), "Key already used", eMB_YESNOCANCEL );
if ( r == eIDYES ) {
// clear the ACTUAL accelerator too!
disconnect_accelerator( name );
// delete the modifier
accelerator = accelerator_null();
// empty the cell of the key binds dialog
GtkTreeIter i;
if ( gtk_tree_model_get_iter_first( GTK_TREE_MODEL( model ), &i ) ) {
for (;; )
{
GValue val;
memset( &val, 0, sizeof( val ) );
gtk_tree_model_get_value( GTK_TREE_MODEL( model ), &i, 0, &val );
const char *thisName = g_value_get_string( &val );;
if ( !strcmp( thisName, name ) ) {
gtk_list_store_set( GTK_LIST_STORE( model ), &i, 1, "", -1 );
}
g_value_unset( &val );
if ( !gtk_tree_model_iter_next( GTK_TREE_MODEL( model ), &i ) ) {
break;
}
}
}
}
else if ( r == eIDCANCEL ) {
// aborted
allow = false;
}
}
}
} verify_visitor( commandName, newAccel, widget, dialog.m_model );
VerifyAcceleratorNotTaken verify_visitor( commandName, newAccel, widget, dialog.m_model );
GlobalShortcuts_foreach( verify_visitor );
gtk_list_store_set( GTK_LIST_STORE( dialog.m_model ), &dialog.m_command_iter, 2, false, -1 );
@ -468,21 +457,16 @@ void DoCommandListDlg(){
StringOutputStream path( 256 );
path << SettingsPath_get() << "commandlist.txt";
globalOutputStream() << "Writing the command list to " << path.c_str() << "\n";
class BuildCommandList : public CommandVisitor
{
TextFileOutputStream m_commandList;
GtkListStore* m_store;
public:
BuildCommandList( const char* filename, GtkListStore* store ) : m_commandList( filename ), m_store( store ){
}
void visit( const char* name, Accelerator& accelerator ){
TextFileOutputStream m_commandList( path.c_str() );
auto buildCommandList = [&m_commandList, store]( const char* name, const Accelerator& accelerator ){
StringOutputStream modifiers;
modifiers << accelerator;
{
GtkTreeIter iter;
gtk_list_store_append( m_store, &iter );
gtk_list_store_set( m_store, &iter, 0, name, 1, modifiers.c_str(), 2, false, 3, 800, -1 );
gtk_list_store_append( store, &iter );
gtk_list_store_set( store, &iter, 0, name, 1, modifiers.c_str(), 2, false, 3, 800, -1 );
}
if ( !m_commandList.failed() ) {
@ -492,10 +476,8 @@ public:
m_commandList << ' ';
m_commandList << modifiers.c_str() << '\n';
}
}
} visitor( path.c_str(), store );
GlobalShortcuts_foreach( visitor );
};
GlobalShortcuts_foreach( buildCommandList );
}
g_object_unref( G_OBJECT( store ) );
@ -541,21 +523,14 @@ void SaveCommandMap( const char* path ){
file << "number=" << COMMANDS_VERSION << "\n";
file << "\n";
file << "[Commands]\n";
class WriteCommandMap : public CommandVisitor
{
TextFileOutputStream& m_file;
public:
WriteCommandMap( TextFileOutputStream& file ) : m_file( file ){
}
void visit( const char* name, Accelerator& accelerator ){
m_file << name << "=";
auto writeCommandMap = [&file]( const char* name, const Accelerator& accelerator ){
file << name << "=";
const char* key = gtk_accelerator_name( accelerator.key, accelerator.modifiers );
m_file << key;
m_file << "\n";
}
} visitor( file );
GlobalShortcuts_foreach( visitor );
file << key;
file << "\n";
};
GlobalShortcuts_foreach( writeCommandMap );
}
}
@ -567,14 +542,14 @@ const char* stringrange_find( const char* first, const char* last, char c ){
return p;
}
class ReadCommandMap : public CommandVisitor
class ReadCommandMap
{
const char* m_filename;
std::size_t m_count;
public:
ReadCommandMap( const char* filename ) : m_filename( filename ), m_count( 0 ){
}
void visit( const char* name, Accelerator& accelerator ){
void operator()( const char* name, Accelerator& accelerator ){
char value[1024];
if ( read_var( m_filename, "Commands", name, value ) ) {
if ( string_empty( value ) ) {

View File

@ -29,12 +29,6 @@ const Accelerator& GlobalShortcuts_insert( const char* name, const Accelerator&
void GlobalShortcuts_register( const char* name, int type ); // 1 = command, 2 = toggle
void GlobalShortcuts_reportUnregistered();
class CommandVisitor
{
public:
virtual void visit( const char* name, Accelerator& accelerator ) = 0;
};
void GlobalCommands_insert( const char* name, const Callback& callback, const Accelerator& accelerator = accelerator_null() );
const Command& GlobalCommands_find( const char* name );