Rewrite selection event code for wxListBox.

Remove ifdef for non-native wxCheckListBox.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42469 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robert Roebling
2006-10-26 20:29:02 +00:00
parent de30344498
commit 470402b996
4 changed files with 102 additions and 290 deletions

View File

@@ -24,10 +24,6 @@
#define wxCHECKLBOX_STRING _T("[ ] ") #define wxCHECKLBOX_STRING _T("[ ] ")
#endif #endif
//Use the native GTK2.0+ checklist?? You should say YYEEESS unless
//there are like some major bugs or something :)
#define wxUSE_NATIVEGTKCHECKLIST 1
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// wxCheckListBox // wxCheckListBox
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -57,9 +53,7 @@ public:
int GetItemHeight() const; int GetItemHeight() const;
#if wxUSE_NATIVEGTKCHECKLIST
void DoCreateCheckList(); void DoCreateCheckList();
#endif
private: private:
DECLARE_DYNAMIC_CLASS(wxCheckListBox) DECLARE_DYNAMIC_CLASS(wxCheckListBox)

View File

@@ -93,7 +93,6 @@ public:
#endif // wxUSE_CHECKLISTBOX #endif // wxUSE_CHECKLISTBOX
bool m_blockEvent; bool m_blockEvent;
bool m_spacePressed;
struct _GtkTreeEntry* GtkGetEntry(int pos) const; struct _GtkTreeEntry* GtkGetEntry(int pos) const;
void GtkInsertItems(const wxArrayString& items, void GtkInsertItems(const wxArrayString& items,

View File

@@ -23,7 +23,6 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// "toggled" // "toggled"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#if wxUSE_NATIVEGTKCHECKLIST
extern "C" { extern "C" {
static void gtk_checklist_toggled(GtkCellRendererToggle *renderer, static void gtk_checklist_toggled(GtkCellRendererToggle *renderer,
gchar *stringpath, gchar *stringpath,
@@ -41,7 +40,6 @@ static void gtk_checklist_toggled(GtkCellRendererToggle *renderer,
listbox->GetEventHandler()->ProcessEvent( new_event ); listbox->GetEventHandler()->ProcessEvent( new_event );
} }
} }
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// wxCheckListBox // wxCheckListBox
@@ -80,7 +78,6 @@ wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id,
style, validator, name ); style, validator, name );
} }
#if wxUSE_NATIVEGTKCHECKLIST
void wxCheckListBox::DoCreateCheckList() void wxCheckListBox::DoCreateCheckList()
{ {
//Create the checklist in our treeview and set up events for it //Create the checklist in our treeview and set up events for it
@@ -154,52 +151,4 @@ int wxCheckListBox::GetItemHeight() const
return height; return height;
} }
#else //NON-NATIVE
bool wxCheckListBox::IsChecked( int index ) const
{
wxCHECK_MSG( m_treeview != NULL, false, wxT("invalid checklistbox") );
GtkTreeEntry* entry = GtkGetEntry(index);
if (entry)
{
wxString str( wxGTK_CONV_BACK( gtk_tree_entry_get_label(entry) ) );
return str.GetChar(1) == wxCHECKLBOX_CHECKED;
}
wxFAIL_MSG(wxT("wrong checklistbox index"));
return false;
}
void wxCheckListBox::Check( int index, bool check )
{
wxCHECK_RET( m_treeview != NULL, wxT("invalid checklistbox") );
GtkTreeEntry* entry = GtkGetEntry(index);
if (entry)
{
wxString str( wxGTK_CONV_BACK( gtk_tree_entry_get_label(entry) ) );
if (check == (str.GetChar(1) == wxCHECKLBOX_CHECKED))
return;
str.SetChar( 1, check ? wxCHECKLBOX_CHECKED : wxCHECKLBOX_UNCHECKED );
gtk_tree_entry_set_label( entry, wxGTK_CONV( str ) );
return;
}
wxFAIL_MSG(wxT("wrong checklistbox index"));
}
int wxCheckListBox::GetItemHeight() const
{
// FIXME
return 22;
}
#endif //wxUSE_NATIVEGTKCHECKLIST
#endif //wxUSE_CHECKLISTBOX #endif //wxUSE_CHECKLISTBOX

View File

@@ -49,11 +49,11 @@ extern bool g_blockEventsOnScroll;
// Macro to tell which row the strings are in (1 if native checklist, 0 if not) // Macro to tell which row the strings are in (1 if native checklist, 0 if not)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST #if wxUSE_CHECKLISTBOX
# define WXLISTBOX_DATACOLUMN_ARG(x) (x->m_hasCheckBoxes ? 1 : 0) # define WXLISTBOX_DATACOLUMN_ARG(x) (x->m_hasCheckBoxes ? 1 : 0)
#else #else
# define WXLISTBOX_DATACOLUMN_ARG(x) (0) # define WXLISTBOX_DATACOLUMN_ARG(x) (0)
#endif // wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST #endif // wxUSE_CHECKLISTBOX
#define WXLISTBOX_DATACOLUMN WXLISTBOX_DATACOLUMN_ARG(this) #define WXLISTBOX_DATACOLUMN WXLISTBOX_DATACOLUMN_ARG(this)
@@ -73,21 +73,10 @@ gtk_listbox_row_activated_callback(GtkTreeView *treeview,
if (g_blockEventsOnDrag) return; if (g_blockEventsOnDrag) return;
if (g_blockEventsOnScroll) return; if (g_blockEventsOnScroll) return;
if (!listbox->m_hasVMT) return; // This is triggered by either a double-click or a space press
//Notes:
//1) This is triggered by either a double-click or a space press
//2) We handle both here because
//2a) in the case of a space/keypress we can't really know
// which item was pressed on because we can't get coords
// from a keyevent
//2b) It seems more correct
int sel = gtk_tree_path_get_indices(path)[0]; int sel = gtk_tree_path_get_indices(path)[0];
if(!listbox->m_spacePressed)
{
//Assume it was double-click
wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, listbox->GetId() ); wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, listbox->GetId() );
event.SetEventObject( listbox ); event.SetEventObject( listbox );
@@ -101,10 +90,10 @@ gtk_listbox_row_activated_callback(GtkTreeView *treeview,
event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry))); event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry)));
if ( listbox->HasClientObjectData() ) if ( listbox->HasClientObjectData() )
event.SetClientObject( event.SetClientObject( (wxClientData*) gtk_tree_entry_get_userdata(entry) );
(wxClientData*) gtk_tree_entry_get_userdata(entry) );
else if ( listbox->HasClientUntypedData() ) else if ( listbox->HasClientUntypedData() )
event.SetClientData( gtk_tree_entry_get_userdata(entry) ); event.SetClientData( gtk_tree_entry_get_userdata(entry) );
g_object_unref (entry); g_object_unref (entry);
} }
else else
@@ -114,83 +103,12 @@ gtk_listbox_row_activated_callback(GtkTreeView *treeview,
} }
} }
else else
{
event.SetInt(-1); event.SetInt(-1);
}
listbox->GetEventHandler()->ProcessEvent( event ); listbox->GetEventHandler()->ProcessEvent( event );
} }
else
{
listbox->m_spacePressed = false; //don't block selection behaviour anymore
//Space was pressed - toggle the appropriate checkbox and the selection
#if wxUSE_CHECKLISTBOX //Do it for both native and non-native
if (listbox->m_hasCheckBoxes)
{
wxCheckListBox *clb = (wxCheckListBox *)listbox;
clb->Check( sel, !clb->IsChecked(sel) );
wxCommandEvent new_event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
new_event.SetEventObject( listbox );
new_event.SetInt( sel );
listbox->GetEventHandler()->ProcessEvent( new_event );
}
#endif // wxUSE_CHECKLISTBOX
if( (((listbox->GetWindowStyleFlag() & wxLB_MULTIPLE) != 0) ||
((listbox->GetWindowStyleFlag() & wxLB_EXTENDED) != 0)) )
{
//toggle the selection + send event
listbox->GtkSetSelection(sel, !listbox->IsSelected( sel ), false);
}
}
}
}
//-----------------------------------------------------------------------------
// "button_press_event"
//-----------------------------------------------------------------------------
extern "C" {
static gint
gtk_listbox_button_press_callback( GtkWidget *widget,
GdkEventButton *gdk_event,
wxListBox *listbox )
{
// don't need to install idle handler, its done from "event" signal
if (g_blockEventsOnDrag) return FALSE;
if (g_blockEventsOnScroll) return FALSE;
if (!listbox->m_hasVMT) return FALSE;
//Just to be on the safe side - it should be unset in the activate callback
//but we don't want any obscure bugs if it doesn't get called somehow...
listbox->m_spacePressed = false;
#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
if ((listbox->m_hasCheckBoxes) && (gdk_event->x < 15) && (gdk_event->type != GDK_2BUTTON_PRESS))
{
GtkTreePath* path;
gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
(gint)gdk_event->x, (gint)gdk_event->y,
&path, NULL, NULL, NULL);
int sel = gtk_tree_path_get_indices(path)[0];
gtk_tree_path_free(path);
wxCheckListBox *clb = (wxCheckListBox *)listbox;
clb->Check( sel, !clb->IsChecked(sel) );
wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
event.SetEventObject( listbox );
event.SetInt( sel );
listbox->GetEventHandler()->ProcessEvent( event );
}
#endif // wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
return FALSE;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -203,13 +121,8 @@ gtk_listbox_key_press_callback( GtkWidget *widget,
GdkEventKey *gdk_event, GdkEventKey *gdk_event,
wxListBox *listbox ) wxListBox *listbox )
{ {
// don't need to install idle handler, its done from "event" signal
if (g_blockEventsOnDrag) return FALSE; if (g_blockEventsOnDrag) return FALSE;
bool ret = false;
if ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) if ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab))
{ {
wxNavigationKeyEvent new_event; wxNavigationKeyEvent new_event;
@@ -218,90 +131,74 @@ gtk_listbox_key_press_callback( GtkWidget *widget,
/* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) ); new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
new_event.SetCurrentFocus( listbox ); new_event.SetCurrentFocus( listbox );
ret = listbox->GetEventHandler()->ProcessEvent( new_event ); if (listbox->GetEventHandler()->ProcessEvent( new_event ))
return TRUE;
} }
if ((gdk_event->keyval == GDK_Return) && (!ret)) return FALSE;
{
// eat return in all modes (RN:WHY?)
ret = true;
}
// Check or uncheck item with SPACE
if (gdk_event->keyval == ' ')
{
//In the keyevent we don't know the index of the item
//and the activated event gets called anyway...
//
//Also, activating with the space causes the treeview to
//unselect all the items and then select the item in question
//wx's behaviour is to just toggle the item's selection state
//and leave the others alone
listbox->m_spacePressed = true;
}
return ret;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// "select" and "deselect" // "changed"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
extern "C" { extern "C" {
static gboolean gtk_listitem_select_cb( GtkTreeSelection* selection, static void
GtkTreeModel* model, gtk_listitem_changed_callback( GtkTreeSelection* selection, wxListBox *listbox )
GtkTreePath* path,
gboolean is_selected,
wxListBox *listbox )
{ {
if (g_isIdle) wxapp_install_idle_handler(); if (g_blockEventsOnDrag) return;
if (!listbox->m_hasVMT) return TRUE; if (listbox->m_blockEvent) return;
if (g_blockEventsOnDrag) return TRUE;
if (listbox->m_spacePressed) return FALSE; //see keyevent callback
if (listbox->m_blockEvent) return TRUE;
// NB: wxdocs explicitly say that this event only gets sent when
// something is actually selected, plus the controls example
// assumes so and passes -1 to the dogetclientdata funcs if not
// OK, so basically we need to do a bit of a run-around here as
// 1) is_selected says whether the item(s?) are CURRENTLY selected -
// i.e. if is_selected is FALSE then the item is going to be
// selected right now!
// 2) However, since it is not already selected and the user
// will expect it to be we need to manually select it and
// return FALSE telling GTK we handled the selection
if (is_selected) return TRUE;
int nIndex = gtk_tree_path_get_indices(path)[0];
GtkTreeEntry* entry = listbox->GtkGetEntry(nIndex);
if(entry)
{
//Now, as mentioned above, we manually select the row that is/was going
//to be selected anyway by GTK
listbox->m_blockEvent = true; //if we don't block events we will lock the
//app due to recursion!!
GtkTreeSelection* selection =
gtk_tree_view_get_selection(listbox->m_treeview);
GtkTreeIter iter;
gtk_tree_model_get_iter(GTK_TREE_MODEL(listbox->m_liststore), &iter, path);
gtk_tree_selection_select_iter(selection, &iter);
listbox->m_blockEvent = false;
//Finally, send the wx event
wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() ); wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
event.SetEventObject( listbox ); event.SetEventObject( listbox );
// indicate whether this is a selection or a deselection if (listbox->HasFlag(wxLB_MULTIPLE) || listbox->HasFlag(wxLB_EXTENDED))
{
wxArrayInt selections;
listbox->GetSelections( selections );
if (selections.GetCount() == 0)
{
// indicate that this is a deselection
event.SetExtraLong( 0 );
event.SetInt( -1 );
listbox->GetEventHandler()->ProcessEvent( event );
return;
}
else
{
// indicate that this is a selection
event.SetExtraLong( 1 );
event.SetInt( selections[0] );
listbox->GetEventHandler()->ProcessEvent( event );
}
}
else
{
int index = listbox->GetSelection();
if (index == wxNOT_FOUND)
{
// indicate that this is a deselection
event.SetExtraLong( 0 );
event.SetInt( -1 );
listbox->GetEventHandler()->ProcessEvent( event );
return;
}
else
{
GtkTreeEntry* entry = listbox->GtkGetEntry( index );
// indicate that this is a selection
event.SetExtraLong( 1 ); event.SetExtraLong( 1 );
event.SetInt(nIndex); event.SetInt( index );
event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry))); event.SetString(wxConvUTF8.cMB2WX(gtk_tree_entry_get_label(entry)));
if ( listbox->HasClientObjectData() ) if ( listbox->HasClientObjectData() )
@@ -314,10 +211,8 @@ static gboolean gtk_listitem_select_cb( GtkTreeSelection* selection,
listbox->GetEventHandler()->ProcessEvent( event ); listbox->GetEventHandler()->ProcessEvent( event );
g_object_unref (entry); g_object_unref (entry);
return FALSE; //We handled it/did it manually
} }
}
return TRUE; //allow selection to change
} }
} }
@@ -419,7 +314,6 @@ void wxListBox::Init()
#if wxUSE_CHECKLISTBOX #if wxUSE_CHECKLISTBOX
m_hasCheckBoxes = false; m_hasCheckBoxes = false;
#endif // wxUSE_CHECKLISTBOX #endif // wxUSE_CHECKLISTBOX
m_spacePressed = false;
} }
bool wxListBox::Create( wxWindow *parent, wxWindowID id, bool wxListBox::Create( wxWindow *parent, wxWindowID id,
@@ -472,10 +366,10 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
//NB: If enabled SetFirstItem doesn't work correctly //NB: If enabled SetFirstItem doesn't work correctly
gtk_tree_view_set_headers_visible(m_treeview, FALSE); gtk_tree_view_set_headers_visible(m_treeview, FALSE);
#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST #if wxUSE_CHECKLISTBOX
if(m_hasCheckBoxes) if(m_hasCheckBoxes)
((wxCheckListBox*)this)->DoCreateCheckList(); ((wxCheckListBox*)this)->DoCreateCheckList();
#endif // wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST #endif // wxUSE_CHECKLISTBOX
// Create the data column // Create the data column
gtk_tree_view_insert_column_with_attributes(m_treeview, -1, "", gtk_tree_view_insert_column_with_attributes(m_treeview, -1, "",
@@ -484,7 +378,7 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
WXLISTBOX_DATACOLUMN, NULL); WXLISTBOX_DATACOLUMN, NULL);
// Now create+set the model (GtkListStore) - first argument # of columns // Now create+set the model (GtkListStore) - first argument # of columns
#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST #if wxUSE_CHECKLISTBOX
if(m_hasCheckBoxes) if(m_hasCheckBoxes)
m_liststore = gtk_list_store_new(2, G_TYPE_BOOLEAN, m_liststore = gtk_list_store_new(2, G_TYPE_BOOLEAN,
GTK_TYPE_TREE_ENTRY); GTK_TYPE_TREE_ENTRY);
@@ -512,9 +406,9 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
GtkTreeSelection* selection = gtk_tree_view_get_selection( m_treeview ); GtkTreeSelection* selection = gtk_tree_view_get_selection( m_treeview );
gtk_tree_selection_set_select_function(selection,
(GtkTreeSelectionFunc)gtk_listitem_select_cb, g_signal_connect_after (selection, "changed",
this, NULL); //NULL == destroycb G_CALLBACK (gtk_listitem_changed_callback), this);
GtkSelectionMode mode; GtkSelectionMode mode;
if (style & wxLB_MULTIPLE) if (style & wxLB_MULTIPLE)
@@ -559,14 +453,11 @@ bool wxListBox::Create( wxWindow *parent, wxWindowID id,
wxListBox::DoInsertItems(wxArrayString(n, choices), 0); // insert initial items wxListBox::DoInsertItems(wxArrayString(n, choices), 0); // insert initial items
//treeview-specific events // generate dclick events
g_signal_connect(m_treeview, "row-activated", g_signal_connect_after(m_treeview, "row-activated",
G_CALLBACK(gtk_listbox_row_activated_callback), this); G_CALLBACK(gtk_listbox_row_activated_callback), this);
// other events // for panel navigation
g_signal_connect (m_treeview, "button_press_event",
G_CALLBACK (gtk_listbox_button_press_callback),
this);
g_signal_connect (m_treeview, "key_press_event", g_signal_connect (m_treeview, "key_press_event",
G_CALLBACK (gtk_listbox_key_press_callback), G_CALLBACK (gtk_listbox_key_press_callback),
this); this);
@@ -624,14 +515,6 @@ void wxListBox::GtkInsertItems(const wxArrayString& items,
{ {
wxString label = items[i]; wxString label = items[i];
#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
if (m_hasCheckBoxes)
{
label.Prepend(wxCHECKLBOX_STRING);
}
#endif // wxUSE_CHECKLISTBOX
GtkTreeEntry* entry = gtk_tree_entry_new(); GtkTreeEntry* entry = gtk_tree_entry_new();
gtk_tree_entry_set_label(entry, wxConvUTF8.cWX2MB(label)); gtk_tree_entry_set_label(entry, wxConvUTF8.cWX2MB(label));
gtk_tree_entry_set_destroy_func(entry, gtk_tree_entry_set_destroy_func(entry,
@@ -644,7 +527,7 @@ void wxListBox::GtkInsertItems(const wxArrayString& items,
GtkTreeIter itercur; GtkTreeIter itercur;
gtk_list_store_insert_before(m_liststore, &itercur, pIter); gtk_list_store_insert_before(m_liststore, &itercur, pIter);
#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST #if wxUSE_CHECKLISTBOX
if (m_hasCheckBoxes) if (m_hasCheckBoxes)
{ {
gtk_list_store_set(m_liststore, &itercur, gtk_list_store_set(m_liststore, &itercur,
@@ -799,11 +682,6 @@ void wxListBox::SetString(unsigned int n, const wxString &string)
wxString label = string; wxString label = string;
#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
if (m_hasCheckBoxes)
label.Prepend(wxCHECKLBOX_STRING);
#endif // wxUSE_CHECKLISTBOX
// RN: This may look wierd but the problem is that the TreeView // RN: This may look wierd but the problem is that the TreeView
// doesn't resort or update when changed above and there is no real // doesn't resort or update when changed above and there is no real
// notification function... // notification function...
@@ -830,14 +708,6 @@ wxString wxListBox::GetString(unsigned int n) const
wxString label = wxGTK_CONV_BACK( gtk_tree_entry_get_label(entry) ); wxString label = wxGTK_CONV_BACK( gtk_tree_entry_get_label(entry) );
#if wxUSE_CHECKLISTBOX && !wxUSE_NATIVEGTKCHECKLIST
// checklistboxes have "[<5B>] " prepended to their lables, remove it
//
// NB: 4 below is the length of wxCHECKLBOX_STRING from wx/gtk/checklst.h
if ( m_hasCheckBoxes )
label.erase(0, 4);
#endif // wxUSE_CHECKLISTBOX
g_object_unref (entry); g_object_unref (entry);
return label; return label;
} }
@@ -1120,7 +990,7 @@ wxSize wxListBox::DoGetBestSize() const
// And just a bit more for the checkbox if present and then some // And just a bit more for the checkbox if present and then some
// (these are rough guesses) // (these are rough guesses)
#if wxUSE_CHECKLISTBOX && wxUSE_NATIVEGTKCHECKLIST #if wxUSE_CHECKLISTBOX
if ( m_hasCheckBoxes ) if ( m_hasCheckBoxes )
{ {
lbWidth += 35; lbWidth += 35;