rewrite GlobalShortcuts_foreach() to use functor semantics
This commit is contained in:
parent
e25f67ca29
commit
64e2eebfb3
|
|
@ -36,27 +36,22 @@
|
||||||
struct ShortcutValue{
|
struct ShortcutValue{
|
||||||
Accelerator accelerator;
|
Accelerator accelerator;
|
||||||
const Accelerator accelerator_default;
|
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 ){
|
ShortcutValue( const Accelerator& a ) : accelerator( a ), accelerator_default( a ), type( 0 ){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef std::map<CopiedString, ShortcutValue> Shortcuts;
|
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;
|
Shortcuts g_shortcuts;
|
||||||
|
|
||||||
const Accelerator& GlobalShortcuts_insert( const char* name, const Accelerator& accelerator ){
|
const Accelerator& GlobalShortcuts_insert( const char* name, const Accelerator& accelerator ){
|
||||||
return ( *g_shortcuts.insert( Shortcuts::value_type( name, ShortcutValue( accelerator ) ) ).first ).second.accelerator;
|
return ( *g_shortcuts.insert( Shortcuts::value_type( name, ShortcutValue( accelerator ) ) ).first ).second.accelerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalShortcuts_foreach( CommandVisitor& visitor ){
|
template<typename Functor>
|
||||||
Shortcuts_foreach( g_shortcuts, visitor );
|
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 ){
|
void GlobalShortcuts_register( const char* name, int type ){
|
||||||
|
|
@ -67,12 +62,9 @@ void GlobalShortcuts_register( const char* name, int type ){
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalShortcuts_reportUnregistered(){
|
void GlobalShortcuts_reportUnregistered(){
|
||||||
for ( Shortcuts::iterator i = g_shortcuts.begin(); i != g_shortcuts.end(); ++i )
|
for ( auto& pair : g_shortcuts )
|
||||||
{
|
if ( pair.second.accelerator.key != 0 && pair.second.type == 0 )
|
||||||
if ( ( *i ).second.accelerator.key != 0 && ( *i ).second.type == 0 ) {
|
globalWarningStream() << "shortcut not registered: " << pair.first.c_str() << "\n";
|
||||||
globalWarningStream() << "shortcut not registered: " << ( *i ).first.c_str() << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::map<CopiedString, Command> Commands;
|
typedef std::map<CopiedString, Command> Commands;
|
||||||
|
|
@ -258,6 +250,59 @@ gboolean accelerator_tree_butt_press( GtkWidget* widget, GdkEventButton* event,
|
||||||
return FALSE;
|
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 ){
|
gboolean accelerator_window_key_press( GtkWidget *widget, GdkEventKey *event, gpointer dialogptr ){
|
||||||
command_list_dialog_t &dialog = *(command_list_dialog_t *) 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
|
// 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
|
// 8. verify the key is still free, show a dialog to ask what to do if not
|
||||||
class VerifyAcceleratorNotTaken : public CommandVisitor
|
VerifyAcceleratorNotTaken verify_visitor( commandName, newAccel, widget, dialog.m_model );
|
||||||
{
|
|
||||||
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 );
|
|
||||||
GlobalShortcuts_foreach( verify_visitor );
|
GlobalShortcuts_foreach( verify_visitor );
|
||||||
|
|
||||||
gtk_list_store_set( GTK_LIST_STORE( dialog.m_model ), &dialog.m_command_iter, 2, false, -1 );
|
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 );
|
StringOutputStream path( 256 );
|
||||||
path << SettingsPath_get() << "commandlist.txt";
|
path << SettingsPath_get() << "commandlist.txt";
|
||||||
globalOutputStream() << "Writing the command list to " << path.c_str() << "\n";
|
globalOutputStream() << "Writing the command list to " << path.c_str() << "\n";
|
||||||
class BuildCommandList : public CommandVisitor
|
|
||||||
{
|
TextFileOutputStream m_commandList( path.c_str() );
|
||||||
TextFileOutputStream m_commandList;
|
auto buildCommandList = [&m_commandList, store]( const char* name, const Accelerator& accelerator ){
|
||||||
GtkListStore* m_store;
|
|
||||||
public:
|
|
||||||
BuildCommandList( const char* filename, GtkListStore* store ) : m_commandList( filename ), m_store( store ){
|
|
||||||
}
|
|
||||||
void visit( const char* name, Accelerator& accelerator ){
|
|
||||||
StringOutputStream modifiers;
|
StringOutputStream modifiers;
|
||||||
modifiers << accelerator;
|
modifiers << accelerator;
|
||||||
|
|
||||||
{
|
{
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
gtk_list_store_append( m_store, &iter );
|
gtk_list_store_append( store, &iter );
|
||||||
gtk_list_store_set( m_store, &iter, 0, name, 1, modifiers.c_str(), 2, false, 3, 800, -1 );
|
gtk_list_store_set( store, &iter, 0, name, 1, modifiers.c_str(), 2, false, 3, 800, -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !m_commandList.failed() ) {
|
if ( !m_commandList.failed() ) {
|
||||||
|
|
@ -492,10 +476,8 @@ public:
|
||||||
m_commandList << ' ';
|
m_commandList << ' ';
|
||||||
m_commandList << modifiers.c_str() << '\n';
|
m_commandList << modifiers.c_str() << '\n';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
} visitor( path.c_str(), store );
|
GlobalShortcuts_foreach( buildCommandList );
|
||||||
|
|
||||||
GlobalShortcuts_foreach( visitor );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref( G_OBJECT( store ) );
|
g_object_unref( G_OBJECT( store ) );
|
||||||
|
|
@ -541,21 +523,14 @@ void SaveCommandMap( const char* path ){
|
||||||
file << "number=" << COMMANDS_VERSION << "\n";
|
file << "number=" << COMMANDS_VERSION << "\n";
|
||||||
file << "\n";
|
file << "\n";
|
||||||
file << "[Commands]\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 );
|
const char* key = gtk_accelerator_name( accelerator.key, accelerator.modifiers );
|
||||||
m_file << key;
|
file << key;
|
||||||
m_file << "\n";
|
file << "\n";
|
||||||
}
|
};
|
||||||
} visitor( file );
|
GlobalShortcuts_foreach( writeCommandMap );
|
||||||
GlobalShortcuts_foreach( visitor );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -567,14 +542,14 @@ const char* stringrange_find( const char* first, const char* last, char c ){
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReadCommandMap : public CommandVisitor
|
class ReadCommandMap
|
||||||
{
|
{
|
||||||
const char* m_filename;
|
const char* m_filename;
|
||||||
std::size_t m_count;
|
std::size_t m_count;
|
||||||
public:
|
public:
|
||||||
ReadCommandMap( const char* filename ) : m_filename( filename ), m_count( 0 ){
|
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];
|
char value[1024];
|
||||||
if ( read_var( m_filename, "Commands", name, value ) ) {
|
if ( read_var( m_filename, "Commands", name, value ) ) {
|
||||||
if ( string_empty( value ) ) {
|
if ( string_empty( value ) ) {
|
||||||
|
|
|
||||||
|
|
@ -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_register( const char* name, int type ); // 1 = command, 2 = toggle
|
||||||
void GlobalShortcuts_reportUnregistered();
|
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() );
|
void GlobalCommands_insert( const char* name, const Callback& callback, const Accelerator& accelerator = accelerator_null() );
|
||||||
const Command& GlobalCommands_find( const char* name );
|
const Command& GlobalCommands_find( const char* name );
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user