Code::Blocks Forums

Developer forums (C::B DEVELOPMENT STRICTLY!) => Development => Topic started by: Alatar on September 28, 2009, 12:15:59 pm

Title: Improvement in TabSwitcher
Post by: Alatar on September 28, 2009, 12:15:59 pm
I modify MainFrame and EditorManager code to add stack-based tab switching to switcher dialog. I think this is more useful and handy then using Alt+Left/Right.
This code may work wrong, but I hope in most cases it would be helpful. I think, this is temporary solution until wxAuiNotebook would be improved.
Modified files in attachments.

[attachment deleted by admin]
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 09, 2010, 07:37:31 am
I have get and apply this patch.
It look working fine. I this it will be better to let old switching tab code, make new one with your source code (into main frame) and adding a command to see it into keyboard managment.
It is really cool to have this possibility for switching tab. Congratulation.
I think it is an evolution really important for Code::Blocks.

If we have a green light to say, ok it will be integrated into official version, I agree to help you to make evolution on it.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 10, 2010, 10:44:37 pm
It's not work if you press CTRL + SHIFT + ALT : taking previous tab in tab order, not in stack base tabs order.
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 10, 2010, 11:59:44 pm
Try to press CTRL+TAB and then (don`t release CTRL) press SHIFT and again TAB.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 11, 2010, 07:25:00 am
Yes, I know that ! I think CTRL + SHIFT + ALT directly have no sense...
I don't know why this patch is not into official codeblocks source code, but I'll work on your patch to propose another patch with new shortcut like "Switch Tabs Stack". Do you agree ?
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 07:53:23 am
To have a change to figure into official Code::Blocks IDE, I have patch your source code :
Change some variable name (Added type, long name).
And I have added a new menu entry into view menu : Switch tabs stack.
Now, the user can choose between current way change to edited file or new one with Switch tabs stack.
This new menu entry is now into shortcut too: The user can change CTRL+TAB shortcut to new Switch tabs stack.
I hope you have correctly tested your source code because I don't test it (new / delete), its seem work fine.
I'll use it intensively for 2 months with 2 developpers for a professionnal project.
We must work together to make your patch into official Code::Blocks IDE : it is awful to work without this patch, its seems very important to me.

Patch :
Code
Index: src/include/editormanager.h
===================================================================
--- src/include/editormanager.h (revision 6077)
+++ src/include/editormanager.h (working copy)
@@ -45,6 +45,20 @@
 struct cbFindReplaceData;
 
 /*
+ * Struct for store tabs stack info
+ */
+struct cbNotebookStack
+{
+    cbNotebookStack(wxWindow* a_pWindow = NULL)
+        : m_pWindow (a_pWindow),
+          m_pNextNotebookStack (NULL)
+    {}
+
+    wxWindow*           m_pWindow;
+    cbNotebookStack*    m_pNextNotebookStack;
+};
+
+/*
  * No description
  */
 class DLLIMPORT EditorManager : public Mgr<EditorManager>, public wxEvtHandler
@@ -59,6 +73,7 @@
         virtual void operator=(const EditorManager& rhs){ cbThrow(_T("Can't assign an EditorManager* !!!")); }
 
         wxAuiNotebook* GetNotebook(){ return m_pNotebook; }
+        cbNotebookStack* GetNotebookStack();
         void CreateMenu(wxMenuBar* menuBar);
         void ReleaseMenu(wxMenuBar* menuBar);
         void Configure();
@@ -174,6 +189,9 @@
         wxFileName FindHeaderSource(const wxArrayString& candidateFilesArray, const wxFileName& activeFile, bool& isCandidate);
 
         wxAuiNotebook* m_pNotebook;
+        cbNotebookStack* m_pNotebookStackHead;
+        cbNotebookStack* m_pNotebookStackTail;
+        size_t m_nNotebookStackSize;
         cbFindReplaceData* m_LastFindReplaceData;
         EditorColourSet* m_Theme;
         ListCtrlLogger* m_pSearchLog;
Index: src/sdk/editormanager.cpp
===================================================================
--- src/sdk/editormanager.cpp (revision 6077)
+++ src/sdk/editormanager.cpp (working copy)
@@ -156,6 +156,9 @@
 
 EditorManager::EditorManager()
         : m_pNotebook(0L),
+        m_pNotebookStackHead(new cbNotebookStack),
+        m_pNotebookStackTail(m_pNotebookStackHead),
+        m_nNotebookStackSize(0),
         m_LastFindReplaceData(0L),
         m_pSearchLog(0),
         m_SearchLogIndex(-1),
@@ -192,6 +195,55 @@
     Manager::Get()->GetConfigManager(_T("editor"))->Write(_T("/zoom"), m_zoom);
 }
 
+cbNotebookStack* EditorManager::GetNotebookStack()
+{
+    bool bFounded = false;
+    wxWindow* pWindow;
+    cbNotebookStack* pNotebookStack;
+    cbNotebookStack* pPrevNotebookStack;
+
+    while(m_nNotebookStackSize != m_pNotebook->GetPageCount()) //Sync stack with Notebook
+    {
+        if(m_nNotebookStackSize < m_pNotebook->GetPageCount())
+        {
+            for(size_t i = 0; i<m_pNotebook->GetPageCount(); ++i)
+            {
+                pWindow = m_pNotebook->GetPage(i);
+                bFounded = false;
+                for (pNotebookStack = m_pNotebookStackHead->m_pNextNotebookStack; pNotebookStack != NULL; pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+                {
+                    if(pWindow == pNotebookStack->m_pWindow)
+                    {
+                        bFounded = true;
+                        break;
+                    }
+                }
+                if(!bFounded)
+                {
+                    m_pNotebookStackTail->m_pNextNotebookStack = new cbNotebookStack(pWindow);
+                    m_pNotebookStackTail = m_pNotebookStackTail->m_pNextNotebookStack;
+                    ++m_nNotebookStackSize;
+                }
+            }
+        }
+        if(m_nNotebookStackSize > m_pNotebook->GetPageCount())
+        {
+            for (pPrevNotebookStack = m_pNotebookStackHead, pNotebookStack = pPrevNotebookStack->m_pNextNotebookStack; pNotebookStack != NULL; pPrevNotebookStack = pNotebookStack, pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+            {
+                if(m_pNotebook->GetPageIndex(pNotebookStack->m_pWindow) == wxNOT_FOUND)
+                {
+                    pPrevNotebookStack->m_pNextNotebookStack = pNotebookStack->m_pNextNotebookStack;
+                    delete pNotebookStack;
+                    --m_nNotebookStackSize;
+                    pNotebookStack = pPrevNotebookStack;
+                }
+            }
+        }
+    }
+
+    return m_pNotebookStackHead->m_pNextNotebookStack;
+}
+
 void EditorManager::CreateMenu(wxMenuBar* menuBar)
 {
 }
@@ -2510,6 +2562,32 @@
     CodeBlocksEvent evt(cbEVT_EDITOR_ACTIVATED, -1, 0, eb);
     Manager::Get()->GetPluginManager()->NotifyPlugins(evt);
 
+    wxWindow* pWindow;
+    cbNotebookStack* pNotebookStack;
+    cbNotebookStack* pPrevNotebookStack;
+    pWindow = m_pNotebook->GetPage(event.GetSelection());
+    for (pPrevNotebookStack = m_pNotebookStackHead, pNotebookStack = pPrevNotebookStack->m_pNextNotebookStack; pNotebookStack != NULL; pPrevNotebookStack = pNotebookStack, pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+    {
+        if(pWindow == pNotebookStack->m_pWindow)
+        {
+            if(m_pNotebookStackTail == pNotebookStack)
+            {
+                m_pNotebookStackTail = pPrevNotebookStack;
+            }
+            pPrevNotebookStack->m_pNextNotebookStack = pNotebookStack->m_pNextNotebookStack;
+            pNotebookStack->m_pNextNotebookStack = m_pNotebookStackHead->m_pNextNotebookStack;
+            m_pNotebookStackHead->m_pNextNotebookStack = pNotebookStack;
+            break;
+        }
+    }
+    if((m_pNotebookStackHead->m_pNextNotebookStack == NULL)||(pWindow != m_pNotebookStackHead->m_pNextNotebookStack->m_pWindow))
+    {
+        pNotebookStack = new cbNotebookStack(pWindow);
+        pNotebookStack->m_pNextNotebookStack = m_pNotebookStackHead->m_pNextNotebookStack;
+        m_pNotebookStackHead->m_pNextNotebookStack = pNotebookStack;
+        ++m_nNotebookStackSize;
+    }
+
     // focus editor on next update event
     m_pData->m_SetFocusFlag = true;
 
@@ -2539,6 +2617,21 @@
         if (!QueryClose(eb))
             event.Veto();
     }
+
+    wxWindow* pWindow;
+    cbNotebookStack* pNotebookStack;
+    cbNotebookStack* pPrevNotebookStack;
+    pWindow = m_pNotebook->GetPage(event.GetSelection());
+    for (pPrevNotebookStack = m_pNotebookStackHead, pNotebookStack = pPrevNotebookStack->m_pNextNotebookStack; pNotebookStack != NULL; pPrevNotebookStack = pNotebookStack, pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+    {
+        if(pWindow == pNotebookStack->m_pWindow)
+        {
+            pPrevNotebookStack->m_pNextNotebookStack = pNotebookStack->m_pNextNotebookStack;
+            delete pNotebookStack;
+            --m_nNotebookStackSize;
+            break;
+        }
+    }
     event.Skip(); // allow others to process it too
 }
 
Index: src/src/main.cpp
===================================================================
--- src/src/main.cpp (revision 6077)
+++ src/src/main.cpp (working copy)
@@ -211,6 +211,7 @@
 int idViewScriptConsole = XRCID("idViewScriptConsole");
 int idViewFocusEditor = XRCID("idViewFocusEditor");
 int idViewSwitchTabs = XRCID("idViewSwitchTabs");
+int idViewSwitchTabsStack = XRCID("idViewSwitchTabsStack");
 int idViewFullScreen = XRCID("idViewFullScreen");
 
 int idSearchFind = XRCID("idSearchFind");
@@ -431,6 +432,7 @@
     EVT_MENU(idViewScriptConsole, MainFrame::OnViewScriptConsole)
     EVT_MENU(idViewFocusEditor, MainFrame::OnFocusEditor)
     EVT_MENU(idViewSwitchTabs, MainFrame::OnSwitchTabs)
+    EVT_MENU(idViewSwitchTabsStack, MainFrame::OnSwitchTabsStack)
     EVT_MENU(idViewFullScreen, MainFrame::OnToggleFullScreen)
 
     EVT_MENU(idSettingsEnvironment, MainFrame::OnSettingsEnvironment)
@@ -4048,6 +4050,68 @@
     }
 }
 
+void MainFrame::OnSwitchTabsStack(wxCommandEvent& event)
+{
+    size_t index = 0;
+    // Get the notebook from the editormanager:
+    wxAuiNotebook* nb = Manager::Get()->GetEditorManager()->GetNotebook();
+    if (!nb)
+        return;
+    cbNotebookStack* pNotebookStack;
+
+    // Create container and add all open editors:
+    wxSwitcherItems items;
+    items.AddGroup(_("Open files"), wxT("editors"));
+    for (pNotebookStack = Manager::Get()->GetEditorManager()->GetNotebookStack() ; pNotebookStack != NULL; pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+    {
+        wxWindow* window = pNotebookStack->m_pWindow;
+        if(nb->GetPageIndex(window) == wxNOT_FOUND)
+            continue;
+        index = nb->GetPageIndex(window);
+        wxString title = nb->GetPageText(index);
+
+        items.AddItem(title, title, index, nb->GetPageBitmap(index)).SetWindow(window);
+    }
+
+    // Select the focused editor:
+    if(items.GetItemCount() > 2)
+    {   // CTRL + TAB directly select the last editor, not the current one
+        items.SetSelection(2);
+    }
+    else
+    {
+        items.SetSelection(items.GetItemCount()-1);
+    }
+
+    // Create the switcher dialog
+    wxSwitcherDialog dlg(items, wxGetApp().GetTopWindow());
+
+    // Ctrl+Tab workaround for non windows platforms:
+    if (platform::cocoa)
+    {
+        dlg.SetModifierKey(WXK_ALT);
+    }
+    else if (platform::gtk)
+    {
+        dlg.SetExtraNavigationKey(wxT(','));
+    }
+
+    // Finally show the dialog:
+    int answer = dlg.ShowModal();
+
+    // If necessary change the selected editor:
+    if ((answer == wxID_OK) && (dlg.GetSelection() != -1))
+    {
+        wxSwitcherItem& item = items.GetItem(dlg.GetSelection());
+        wxWindow* win = item.GetWindow();
+        if(win)
+        {
+            nb->SetSelection(item.GetId());
+            win->SetFocus();
+        }
+    }
+}
+
 void MainFrame::OnToggleFullScreen(wxCommandEvent& event)
 {
     ShowFullScreen( !IsFullScreen(), wxFULLSCREEN_NOTOOLBAR// | wxFULLSCREEN_NOSTATUSBAR
Index: src/src/main.h
===================================================================
--- src/src/main.h (revision 6077)
+++ src/src/main.h (working copy)
@@ -180,6 +180,7 @@
         void OnToggleStatusBar(wxCommandEvent& event);
         void OnFocusEditor(wxCommandEvent& event);
         void OnSwitchTabs(wxCommandEvent& event);
+        void OnSwitchTabsStack(wxCommandEvent& event);
         void OnToggleFullScreen(wxCommandEvent& event);
 
         // plugin events
Index: src/src/resources/main_menu.xrc
===================================================================
--- src/src/resources/main_menu.xrc (revision 6077)
+++ src/src/resources/main_menu.xrc (working copy)
@@ -538,6 +538,10 @@
         <accel>Ctrl+Tab</accel>
         <help>Switch between open editor tabs</help>
       </object>
+      <object class="wxMenuItem" name="idViewSwitchTabsStack">
+        <label>Switch tabs stack</label>
+        <help>Switch between open editor tabs with sorting of previous used documents</help>
+      </object>
     </object>
     <object class="wxMenu" name="menu_search">
       <label>Sea&amp;rch</label>

How to propose this patch and how to get feed back to know why it is refused and what shall we do to make it accepted ?
This patch has advantage to let the current way of tab changing, just added new one. (yours).

Thanks to give me your feedback.
Feneck91
Title: Re: Improvement in TabSwitcher
Post by: MortenMacFly on January 12, 2010, 08:33:31 am
How to propose this patch and how to get feed back to know why it is refused and what shall we do to make it accepted ?
Via the patch tracker here:
http://developer.berlios.de/patch/?group_id=5358

The original patch is here:
http://developer.berlios.de/patch/?func=detailpatch&patch_id=2902&group_id=5358

Once it got assigned you will get an email automatically if something changes. You can also subscribe to other patches.

Please post a comment in the original patch and/or update the patch there accordingly (only possible with the help of alatar_).

BTW: You'll need to register with BerliOS to have an account which is needed to post patches / bugs.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 09:15:36 am
Alastar, are you agree to work together ?
I let you test my patch and accept or refuse it.
Title: Re: Improvement in TabSwitcher
Post by: MortenMacFly on January 12, 2010, 09:15:47 am
Change some variable name (Added type, long name).
And I have added a new menu entry into view menu : Switch tabs stack.
This is not the default for the CTRL+TAB shortcut. Is this on purpose? I guess it'd be more intuitive if it would. So the other option become an... erm... option.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 09:55:29 am
I'm french, I don't know what is erm option ... is it means obsolet ?
I don't know why Alatar patch is not validate into Code:Blocks...
So, 3 differents ways :
1> Replace the actual CTRL+TAB with a new one with stack recording. The old way was also not supported. This is the alatar patch.
2> Let the current CTRL+TAB working like it actually works and propose another way, the user can custumize with shortcut and so, replace actual CTRL+TAB working by new one. This is my patch.
3> Let the current CTRL+TAB working like it actually works but remove its shortcut and assign it to new working. If the user want to keep old way of CTRL+TAB, he can custumize shortcut to old way. I can do this patch if you want, but I'm not sure that only modify xrc will work if the user has assign another key to this shortcut.

I thought that if this patch was not into Code::Blocks it was because we should not modify currents working of Code::Blocks, so why I propose the patch (2).

What shall we do ?
Title: Re: Improvement in TabSwitcher
Post by: MortenMacFly on January 12, 2010, 10:07:13 am
What shall we do ?
I'd vote for 3>.

I've modified the patch again to make re-use of duplicate code and format it a bit. (BTW: I absolutely don't like initialisation of variables in the for () block btw...). The state of the patch in "pending" (being processed). The reason is simple: Its untested under Linux. Once this is done it may make it into trunk. That's very likely from my point of view hence the other devs can object.
Title: Re: Improvement in TabSwitcher
Post by: Jenna on January 12, 2010, 10:24:37 am
I vote for keeping the Ctrl + Tab behaviour as it is by default and change it only if the user wants it.

Two causes for this:

1. changing an existing behaviour is normally not a good idea and can confuse other users and will most likely lead to "bug"-reports,

2. the default for Ctrl+[Shift+]Tab in most applications is to switch between the tabs directly and not to switch between the tabs accessed as last.

@Martin: it would be nice, if you can send me your cleaned up patch to test it on linux.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 10:45:29 am
I agree with jens, I think, let the user take the decision of way of changing documents by pressing CTRL + TAB.
It was why I propose the second patch.
Quote
2. the default for Ctrl+[Shift+]Tab in most applications is to switch between the tabs directly and not to switch between the tabs accessed as last.
Not true, Visual C++ / Netbeans work like this, last accessed, first on tab order...
Quote
@Martin: it would be nice, if you can send me your cleaned up patch to test it on linux.
I have modified the source code to be more understanding, if you have patched this source, please post the new version.

Thanks.

Nb : Some problems could occurs with the function void MainFrame::CreateMenubar()
Quote
   // Ctrl+Tab workaround for non windows platforms:
    if ((platform::carbon) || (platform::gtk))
    {
        // Find the menu item for tab switching:
        tmpidx = mbar->FindMenu(_("&View"));
        if (tmpidx != wxNOT_FOUND)
        {
            wxMenu* view = mbar->GetMenu(tmpidx);
            wxMenuItem* switch_item = view->FindItem(idViewSwitchTabs);
            if (switch_item)
            {
                // Change the accelerator for this menu item:
                wxString accel;
                if (platform::carbon)
                    accel = wxT("Alt+Tab");
                else if (platform::gtk)
                    accel = wxT("Ctrl+,");
                switch_item->SetItemLabel(wxString(_("S&witch Tabs")) + wxT("\t") + accel);
            }
        }
    }
What shall we do here ? Testing on wich switching tab type the accel is for and modify it and only it ? Or let it like this and accelerators will overwrite it if the shortcut is modified ?

Thanks for your reply.
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 12, 2010, 06:51:04 pm
Alastar, are you agree to work together ?
I let you test my patch and accept or refuse it.
Agree of course. I try to help with further improvement patch.
I'd vote for 3>.
I`m too.
Morten, where is last version of this patch?
Feneck91, I think, there is not good idea to add it into menu - it must be in Settings->Invironment, where it was before migrating from wxFlatNotebook to wxAuiNotebook.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 07:53:17 pm
I'd vote for 4 !
4> I think like you : let only one menu / shortcut, but add an option to know how to manage tabs :
- Could add into : Setting / Editor... / General Setting .... but where put this option ?
- Could add into : Setting / Environment ... / General Setting .... but where put this option ? After Allow only one running instance or in Notebook appearance.
If you reply, I could make the patch !


I think it is the better solution. question is : where whe should put this option, and how describe it ?

Morten, where is last version of this patch ?
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 12, 2010, 08:18:46 pm
Oops... I mean exactly way 4, but don`t understand that post correctly (I don`t know English well). Of course we must simply change event handler depending on checkbox in Environment settings panel. (with using dynamic event handling, or with simply IF-THEN-ELSE in static handler).
In earliest version s it was in "Notebook appearance", if I`m not mistake.
Title: Re: Improvement in TabSwitcher
Post by: MortenMacFly on January 12, 2010, 09:03:03 pm
Morten, where is last version of this patch ?
I need to be at home and need to have some spare time for that. Both is not the case atm... be patient.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 09:04:04 pm
I agree with you....
I re-install old 8.02 version....
I fact, this option was used as Use Smart Tab-switching scheme. I can re-add it !
Where are you come from ? I'm french, not english...
(http://dk9.ti1ca.com/get/82.235.166.110/xq5edkjw/Notebook_appearance.JPG)
It was removed when notebook was changed ?

If then else is the simplest way, no need to make it complicated !
Looking for a new patch.....
Post here in few hours....

Another thing : the window that is opened when we press CTRL+TAB is bugged .. if the mouse is over, even if the mouse not moved, select automatically a window that the user doesn't want.

Ok ?
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 12, 2010, 10:10:22 pm
SmartTabSwitch is now using by Alt+Left/Right. I don`t know why. wxFlatNotebook has a build-in tab stack which was used by tab switcher. In wxAuiNotebook this feature is missed.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 10:50:43 pm
What should I do ? put this check box again ? Another way ?
Where are you from ?
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 12, 2010, 11:04:05 pm
I think you should place check box with something like "Use stack-based CTRL-TAB".

I`m from Russia.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 12, 2010, 11:25:36 pm
Nice to meet you Alatar.
I have added "Use stacked based tab-switching" into Setting/Environment/Notebooks appearance
Correct (need to test) the bug of opened dialog with window list : the user need to move the mouse to select an item.
Do you see this problem ? Put your mouse over the 4th item and select CTRL+TAB, you will see, you always select the 4th item.... To correctly use CTRL+TAB your mouse must not be in the middle of the screen, else it doesn't work.
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 13, 2010, 06:18:28 am
It is not a bug, it is a feature =) I think this must be controlled in Settings to.  Something like "Select document in tab switcher when mouse hover".
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 13, 2010, 09:56:20 am
It is not a bug, it is a feature =) I think this must be controls in Settings to.  Something like "Select document in tab switcher when mouse hover".
Yes, when mouse is over.... but if your mouse is in the center on the window and you don't touch it, you are not able to select the item you want, its takes automatically the item under the mouse, even you don't move the mouse. If you press CTRL+TAB and select another item and unpress CTRL, it don't select the highlight item because the mouse is over another one..... For me it is a bug !
I modify it : you can choose item with the mouse ONLY if you move the mouse over a rect of 3 pixel width/height. If you unpress CTRL and don't move the mouse, it don't try to select the item under the mouse cursor, let the current selected one....
Testing and propose a patch here....
With : this patch
and  : "Use stacked based tab-switching" added option into Setting/Environment/Notebooks appearance
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 13, 2010, 11:10:32 am
you can choose item with the mouse ONLY if you move the mouse over a rect of 3 pixel width/height.

Good idea.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 13, 2010, 12:38:03 pm
Ok, tested ! It's work perfectly.
This patch contains :
- "Use stacked based tab-switching" added option into Setting/Environment/Notebooks appearance
- Depending of option "Use stacked based tab-switching", the CTRL+TAB has old comportment if unchecked, if checked it has the stacked  tab switching comportment.
- Bug fix : When window selection opened (when pressing CTRL+TAB), it doesn't select the item under the mouse cursor automatically, only if the user move the mouse cursor more that 3 pixels width/height.
- Bug fix : When window selection is open (when pressing CTRL+TAB), when selecting an item with the mouse (just move, without pressing button), if the user select another window by pressing CTRL+TAB again, release CTRL now select the highlight item not the item under the mouse cursor.
Patch :
Code
Index: src/include/editormanager.h
===================================================================
--- src/include/editormanager.h (revision 6080)
+++ src/include/editormanager.h (working copy)
@@ -45,6 +45,20 @@
 struct cbFindReplaceData;
 
 /*
+ * Struct for store tabs stack info
+ */
+struct cbNotebookStack
+{
+    cbNotebookStack(wxWindow* a_pWindow = NULL)
+        : m_pWindow (a_pWindow),
+          m_pNextNotebookStack (NULL)
+    {}
+
+    wxWindow*           m_pWindow;
+    cbNotebookStack*    m_pNextNotebookStack;
+};
+
+/*
  * No description
  */
 class DLLIMPORT EditorManager : public Mgr<EditorManager>, public wxEvtHandler
@@ -59,6 +73,7 @@
         virtual void operator=(const EditorManager& rhs){ cbThrow(_T("Can't assign an EditorManager* !!!")); }
 
         wxAuiNotebook* GetNotebook(){ return m_pNotebook; }
+        cbNotebookStack* GetNotebookStack();
         void CreateMenu(wxMenuBar* menuBar);
         void ReleaseMenu(wxMenuBar* menuBar);
         void Configure();
@@ -174,6 +189,9 @@
         wxFileName FindHeaderSource(const wxArrayString& candidateFilesArray, const wxFileName& activeFile, bool& isCandidate);
 
         wxAuiNotebook* m_pNotebook;
+        cbNotebookStack* m_pNotebookStackHead;
+        cbNotebookStack* m_pNotebookStackTail;
+        size_t m_nNotebookStackSize;
         cbFindReplaceData* m_LastFindReplaceData;
         EditorColourSet* m_Theme;
         ListCtrlLogger* m_pSearchLog;
Index: src/sdk/editormanager.cpp
===================================================================
--- src/sdk/editormanager.cpp (revision 6080)
+++ src/sdk/editormanager.cpp (working copy)
@@ -156,6 +156,9 @@
 
 EditorManager::EditorManager()
         : m_pNotebook(0L),
+        m_pNotebookStackHead(new cbNotebookStack),
+        m_pNotebookStackTail(m_pNotebookStackHead),
+        m_nNotebookStackSize(0),
         m_LastFindReplaceData(0L),
         m_pSearchLog(0),
         m_SearchLogIndex(-1),
@@ -192,6 +195,55 @@
     Manager::Get()->GetConfigManager(_T("editor"))->Write(_T("/zoom"), m_zoom);
 }
 
+cbNotebookStack* EditorManager::GetNotebookStack()
+{
+    bool bFounded = false;
+    wxWindow* pWindow;
+    cbNotebookStack* pNotebookStack;
+    cbNotebookStack* pPrevNotebookStack;
+
+    while(m_nNotebookStackSize != m_pNotebook->GetPageCount()) //Sync stack with Notebook
+    {
+        if(m_nNotebookStackSize < m_pNotebook->GetPageCount())
+        {
+            for(size_t i = 0; i<m_pNotebook->GetPageCount(); ++i)
+            {
+                pWindow = m_pNotebook->GetPage(i);
+                bFounded = false;
+                for (pNotebookStack = m_pNotebookStackHead->m_pNextNotebookStack; pNotebookStack != NULL; pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+                {
+                    if(pWindow == pNotebookStack->m_pWindow)
+                    {
+                        bFounded = true;
+                        break;
+                    }
+                }
+                if(!bFounded)
+                {
+                    m_pNotebookStackTail->m_pNextNotebookStack = new cbNotebookStack(pWindow);
+                    m_pNotebookStackTail = m_pNotebookStackTail->m_pNextNotebookStack;
+                    ++m_nNotebookStackSize;
+                }
+            }
+        }
+        if(m_nNotebookStackSize > m_pNotebook->GetPageCount())
+        {
+            for (pPrevNotebookStack = m_pNotebookStackHead, pNotebookStack = pPrevNotebookStack->m_pNextNotebookStack; pNotebookStack != NULL; pPrevNotebookStack = pNotebookStack, pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+            {
+                if(m_pNotebook->GetPageIndex(pNotebookStack->m_pWindow) == wxNOT_FOUND)
+                {
+                    pPrevNotebookStack->m_pNextNotebookStack = pNotebookStack->m_pNextNotebookStack;
+                    delete pNotebookStack;
+                    --m_nNotebookStackSize;
+                    pNotebookStack = pPrevNotebookStack;
+                }
+            }
+        }
+    }
+
+    return m_pNotebookStackHead->m_pNextNotebookStack;
+}
+
 void EditorManager::CreateMenu(wxMenuBar* menuBar)
 {
 }
@@ -2510,6 +2562,32 @@
     CodeBlocksEvent evt(cbEVT_EDITOR_ACTIVATED, -1, 0, eb);
     Manager::Get()->GetPluginManager()->NotifyPlugins(evt);
 
+    wxWindow* pWindow;
+    cbNotebookStack* pNotebookStack;
+    cbNotebookStack* pPrevNotebookStack;
+    pWindow = m_pNotebook->GetPage(event.GetSelection());
+    for (pPrevNotebookStack = m_pNotebookStackHead, pNotebookStack = pPrevNotebookStack->m_pNextNotebookStack; pNotebookStack != NULL; pPrevNotebookStack = pNotebookStack, pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+    {
+        if(pWindow == pNotebookStack->m_pWindow)
+        {
+            if(m_pNotebookStackTail == pNotebookStack)
+            {
+                m_pNotebookStackTail = pPrevNotebookStack;
+            }
+            pPrevNotebookStack->m_pNextNotebookStack = pNotebookStack->m_pNextNotebookStack;
+            pNotebookStack->m_pNextNotebookStack = m_pNotebookStackHead->m_pNextNotebookStack;
+            m_pNotebookStackHead->m_pNextNotebookStack = pNotebookStack;
+            break;
+        }
+    }
+    if((m_pNotebookStackHead->m_pNextNotebookStack == NULL)||(pWindow != m_pNotebookStackHead->m_pNextNotebookStack->m_pWindow))
+    {
+        pNotebookStack = new cbNotebookStack(pWindow);
+        pNotebookStack->m_pNextNotebookStack = m_pNotebookStackHead->m_pNextNotebookStack;
+        m_pNotebookStackHead->m_pNextNotebookStack = pNotebookStack;
+        ++m_nNotebookStackSize;
+    }
+
     // focus editor on next update event
     m_pData->m_SetFocusFlag = true;
 
@@ -2539,6 +2617,21 @@
         if (!QueryClose(eb))
             event.Veto();
     }
+
+    wxWindow* pWindow;
+    cbNotebookStack* pNotebookStack;
+    cbNotebookStack* pPrevNotebookStack;
+    pWindow = m_pNotebook->GetPage(event.GetSelection());
+    for (pPrevNotebookStack = m_pNotebookStackHead, pNotebookStack = pPrevNotebookStack->m_pNextNotebookStack; pNotebookStack != NULL; pPrevNotebookStack = pNotebookStack, pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+    {
+        if(pWindow == pNotebookStack->m_pWindow)
+        {
+            pPrevNotebookStack->m_pNextNotebookStack = pNotebookStack->m_pNextNotebookStack;
+            delete pNotebookStack;
+            --m_nNotebookStackSize;
+            break;
+        }
+    }
     event.Skip(); // allow others to process it too
 }
 
Index: src/src/environmentsettingsdlg.cpp
===================================================================
--- src/src/environmentsettingsdlg.cpp (revision 6080)
+++ src/src/environmentsettingsdlg.cpp (working copy)
@@ -170,6 +170,7 @@
     // tab "Notebook"
     XRCCTRL(*this, "cmbEditorTabs", wxComboBox)->SetSelection(cfg->ReadInt(_T("/environment/tabs_style"), 0));
     XRCCTRL(*this, "chkListTabs", wxCheckBox)->SetValue(cfg->ReadBool(_T("/environment/tabs_list"), 0));
+    XRCCTRL(*this, "chkStackedBasedTabSwitching", wxCheckBox)->SetValue(cfg->ReadBool(_T("/environment/stacked_based_tab_switching"), 0));
 
     // tab "Docking"
     XRCCTRL(*this, "spnAuiBorder", wxSpinCtrl)->SetValue(cfg->ReadInt(_T("/environment/aui/border_size"), m_pArt->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE)));
@@ -409,6 +410,7 @@
         // tab "Appearence"
         cfg->Write(_T("/environment/tabs_style"),           (int)XRCCTRL(*this, "cmbEditorTabs", wxComboBox)->GetSelection());
         cfg->Write(_T("/environment/tabs_list"),           (bool)XRCCTRL(*this, "chkListTabs", wxCheckBox)->GetValue());
+        cfg->Write(_T("/environment/stacked_based_tab_switching"),(bool)XRCCTRL(*this, "chkStackedBasedTabSwitching", wxCheckBox)->GetValue());
         cfg->Write(_T("/environment/aui/border_size"),          (int)XRCCTRL(*this, "spnAuiBorder", wxSpinCtrl)->GetValue());
         cfg->Write(_T("/environment/aui/sash_size"),            (int)XRCCTRL(*this, "spnAuiSash", wxSpinCtrl)->GetValue());
         cfg->Write(_T("/environment/aui/caption_size"),         (int)XRCCTRL(*this, "spnAuiCaption", wxSpinCtrl)->GetValue());
Index: src/src/main.cpp
===================================================================
--- src/src/main.cpp (revision 6080)
+++ src/src/main.cpp (working copy)
@@ -4010,27 +4010,64 @@
     // Create container and add all open editors:
     wxSwitcherItems items;
     items.AddGroup(_("Open files"), wxT("editors"));
-    for (size_t i = 0; i < nb->GetPageCount(); ++i)
-    {
-        wxString title = nb->GetPageText(i);
-        wxWindow* window = nb->GetPage(i);
 
-        items.AddItem(title, title, i, nb->GetPageBitmap(i)).SetWindow(window);
+    ConfigManager* pCfg = Manager::Get()->GetConfigManager(_T("app"));
+    if (!pCfg->ReadBool(_T("/environment/stacked_based_tab_switching")))
+    {   // Switch tabs editor with tab order
+        for (size_t i = 0; i < nb->GetPageCount(); ++i)
+        {
+            wxString title = nb->GetPageText(i);
+            wxWindow* window = nb->GetPage(i);
+
+            items.AddItem(title, title, i, nb->GetPageBitmap(i)).SetWindow(window);
+        }
+
+        // Select the focused editor:
+        int idx = items.GetIndexForFocus();
+        if (idx != wxNOT_FOUND)
+        {
+            items.SetSelection(idx);
+        }
     }
+    else
+    {   // Switch tabs editor with last used order
+        size_t nIndex = 0;
+        cbNotebookStack* pNotebookStack;
+        for (pNotebookStack = Manager::Get()->GetEditorManager()->GetNotebookStack() ; pNotebookStack != NULL; pNotebookStack = pNotebookStack->m_pNextNotebookStack)
+        {
+            nIndex = nb->GetPageIndex(pNotebookStack->m_pWindow);
+            if (nIndex == (size_t) wxNOT_FOUND)
+            {
+                continue;
+            }
+            wxString title = nb->GetPageText(nIndex);
 
-    // Select the focused editor:
-    int idx = items.GetIndexForFocus();
-    if (idx != wxNOT_FOUND)
-        items.SetSelection(idx);
+            items.AddItem(title, title, nIndex, nb->GetPageBitmap(nIndex)).SetWindow(pNotebookStack->m_pWindow);
+        }
 
+        // Select the focused editor:
+        if(items.GetItemCount() > 2)
+        {   // CTRL + TAB directly select the last editor, not the current one
+            items.SetSelection(2);
+        }
+        else
+        {
+            items.SetSelection(items.GetItemCount()-1);
+        }
+    }
+
     // Create the switcher dialog
     wxSwitcherDialog dlg(items, wxGetApp().GetTopWindow());
 
     // Ctrl+Tab workaround for non windows platforms:
     if (platform::cocoa)
+    {
         dlg.SetModifierKey(WXK_ALT);
+    }
     else if (platform::gtk)
+    {
         dlg.SetExtraNavigationKey(wxT(','));
+    }
 
     // Finally show the dialog:
     int answer = dlg.ShowModal();
Index: src/src/resources/env_settings.xrc
===================================================================
--- src/src/resources/env_settings.xrc (revision 6080)
+++ src/src/resources/env_settings.xrc (working copy)
@@ -398,6 +398,13 @@
  <flag>wxALL|wxALIGN_LEFT|wxALIGN_TOP</flag>
  <border>8</border>
  </object>
+ <object class="sizeritem">
+ <object class="wxCheckBox" name="chkStackedBasedTabSwitching">
+ <label>Use stacked based tab-switching</label>
+ </object>
+ <flag>wxALL|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>8</border>
+ </object>
  </object>
  </object>
  <label>Notebooks appearance</label>
Index: src/src/switcherdlg.cpp
===================================================================
--- src/src/switcherdlg.cpp (revision 6080)
+++ src/src/switcherdlg.cpp (working copy)
@@ -509,26 +509,45 @@
 
         Refresh();
     }
-    else
-    {
-        int idx = m_items.HitTest(event.GetPosition());
+    else if (event.GetButton() == wxMOUSE_BTN_NONE)
+    {   // Mouse move
+        bool bCanSelectItem = true;
+        if (m_ptMouse.x != -2 && m_ptMouse.y != -2)
+        {   // If ==-2 => Don't select item on mouse pointer : used when user select the window with keyboard
+            if (m_ptMouse.x != -1 && m_ptMouse.y != -1)
+            {   // If ==-1 => The client already move the mouse, select the item under the mouse cursor
+                wxPoint ptCurrent = ClientToScreen(event.GetPosition());
+                if (abs(ptCurrent.x - m_ptMouse.x) >= 3 || abs(ptCurrent.y - m_ptMouse.y) >= 3)
+                {   // the user has moved the mouse over a 3 pixels square
+                    m_ptMouse.x = m_ptMouse.y = -1; // Accept to select an item
+                }
+                else
+                {   // Select this item is not allowed for the moment, the user must move the mouse
+                    bCanSelectItem = false;
+                }
+            }
 
-        if (idx != wxNOT_FOUND)
-        {
-            m_items.SetSelection(idx);
+            if (bCanSelectItem)
+            {
+                int idx = m_items.HitTest(event.GetPosition());
 
-            GenerateSelectionEvent();
+                if (idx != wxNOT_FOUND)
+                {
+                    m_items.SetSelection(idx);
 
-            Refresh();
-        }
+                    GenerateSelectionEvent();
 
-        if (event.LeftDown())
-        {
-            SendCloseEvent();
-
-            SetFocus();
+                    Refresh();
+                }
+            }
         }
     }
+    else if (event.LeftDown())
+    {
+        m_ptMouse.x = m_ptMouse.y = -1; // Accept to select an item
+        SendCloseEvent();
+        SetFocus();
+    }
 }
 
 void wxMultiColumnListCtrl::OnChar(wxKeyEvent& WXUNUSED(event))
@@ -541,6 +560,8 @@
     {
         if (event.GetKeyCode() == GetModifierKey())
         {
+            // The window will close, don't select the item under mouse pointer
+            m_ptMouse.x = m_ptMouse.y = -2;
             SendCloseEvent();
         }
         event.Skip();
@@ -549,6 +570,9 @@
 
     if (event.GetKeyCode() == WXK_ESCAPE || event.GetKeyCode() == WXK_RETURN)
     {
+        // The window will close, don't select the item under mouse pointer
+        m_ptMouse.x = m_ptMouse.y = -2;
+
         if (event.GetKeyCode() == WXK_ESCAPE)
             m_items.SetSelection(-1);
 
@@ -802,6 +826,7 @@
     m_overallSize = wxSize(200, 100);
     m_modifierKey = WXK_CONTROL;
     m_extraNavigationKey = 0;
+    m_ptMouse = wxGetMousePosition();
 }
 
 /*!
Index: src/src/switcherdlg.h
===================================================================
--- src/src/switcherdlg.h (revision 6080)
+++ src/src/switcherdlg.h (working copy)
@@ -233,7 +233,15 @@
     void SendCloseEvent();
 
 protected:
-
+    /**
+     * Mouse point initialized on Init function.
+     *
+     * Used because if the mouse is over the dialog when it's opened, it automatically
+     * select the item under the mouse pointer.
+     * Recording the mouse pointer position when the dialog is opened prevent this :
+     * select the item only if the user move the mouse.
+    */
+    wxPoint             m_ptMouse;
     wxSwitcherItems     m_items;
     wxSize              m_overallSize;
     int                 m_extraNavigationKey;

Thanks for all to give me Feedback.
I place comments into my Codeblocks source patch. I don't see very often comments into source code (specially into .h), I don't know if it's good or not to place comments (into javadoc format).
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 14, 2010, 10:31:42 pm
Added new version of patch to tracker - http://developer.berlios.de/patch/index.php?func=detailpatch&patch_id=2902&group_id=5358

Included all changes from Feneck91`s last patch.
Some code cleanup, simplify code in functions GetNotebookStack(), OnPageChanged() and OnPageClose().
Added stack deletion and rebuild stack function.
If we not using stack based tab switching, we don`t manage stack. But I don`t know, where should I rebuild stack, when it turn on in settings. For now I place this code into EnvironmentSettingsDlg::EndModal(), but it seems wrong - there are no such code. Marting, what do you think?

Feneck91, by the way, don`t use long camel case names for local variables - this is not Code::Blocks style =) .
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 15, 2010, 05:03:59 am
Code
Feneck91, by the way, don`t use long camel case names for local variables
I'm sorry, I didn't understand. What is camel  case name ?
Title: Re: Improvement in TabSwitcher
Post by: Alatar on January 15, 2010, 05:57:26 am
I'm sorry, I didn't understand. What is camel  case name ?
ItIsSameAsMixedCase ;)
http://en.wikipedia.org/wiki/CamelCase
Title: Re: Improvement in TabSwitcher
Post by: MortenMacFly on January 15, 2010, 06:38:08 am
Code
Feneck91, by the way, don`t use [b]long[/b] camel case names for local variables
I'm sorry, I didn't understand. What is camel  case name ?
I think whar he meant was the long names. As variable names that are too long make the code harder to read.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on March 06, 2010, 07:38:27 pm
Trying to apply this patch now... very complex to apply because a lot of conflits.
Alatar, this patch will be integrated by code::blocks teams or not ?
Title: Re: Improvement in TabSwitcher
Post by: Alatar on March 07, 2010, 08:33:01 am
I don`t know... This is question for Morten.
I can try to generate new patch and update it in tracker, but this will take some time - my working copy now has more fixes =).
Title: Re: Improvement in TabSwitcher
Post by: MortenMacFly on March 07, 2010, 05:33:39 pm
Alatar, this patch will be integrated by code::blocks teams or not ?
I don`t know... This is question for Morten.
I would have no objections. However, this patch is still untested under Linux, that's why I didn't apply it so far. However, I am working with it under Windows on everyday basis - no issues.

my working copy now has more fixes =).
Which in particular? Meaning: Are they related to the tabswitch? This would put it on hold then.
Title: Re: Improvement in TabSwitcher
Post by: Alatar on March 07, 2010, 08:05:48 pm
my working copy now has more fixes =).
Which in particular? Meaning: Are they related to the tabswitch? This would put it on hold then.

One of them is related to the tabswitcher, but not to the stack-based switching (simple add some info about tab to bottom area of tab switcher). I want to post it after this one would be accepted or refused.
http://forums.codeblocks.org/index.php/topic,11885.0.html
Title: Re: Improvement in TabSwitcher
Post by: Alatar on March 07, 2010, 08:35:59 pm
And by the way, I still don`t know where should I place code for stack rebuild when stack-based switching turn on/off.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on March 07, 2010, 09:15:54 pm
My team work with this code for 2 months (4 peaples), without any problems on Windows XP / Windows 2000.
Title: Re: Improvement in TabSwitcher
Post by: oBFusCATed on March 07, 2010, 10:30:17 pm
I can test the thing on linux, but I'm not sure where exactly to find the patch...
Title: Re: Improvement in TabSwitcher
Post by: Alatar on March 08, 2010, 06:32:36 am
I can test the thing on linux, but I'm not sure where exactly to find the patch...
http://developer.berlios.de/patch/index.php?func=detailpatch&patch_id=2902&group_id=5358
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on March 08, 2010, 07:55:18 am
If you can merge patch because there is a lot of changes since this patch was done.
I have no time to make new one because I'm at the end of working project and I'm in a hurry :-(
If the patch is updated, I'll put it into the client documentation to explain how to re-build developpment platform up to date.
Title: Re: Improvement in TabSwitcher
Post by: Alatar on March 10, 2010, 08:50:00 pm
Regenerated for r6187.
Added some features that don`t directly related to stack-based tab switching (I have no time to separate patches):
 - add tab description to the bottom area of tab switcher dialog
 - fix selected item font colour in the tab list

http://developer.berlios.de/patch/index.php?func=detailpatch&patch_id=2902&group_id=5358
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on March 10, 2010, 10:19:04 pm
COOOOOOOOOOOL !!
Really cool, your patch is apply without any problems !
Recommanded for everyone !

Thanks for your work !
Title: Re: Improvement in TabSwitcher
Post by: richarduk on March 27, 2010, 06:36:13 pm
Hi, I've applied the patch to it does not seem to work. The option is in the settings dialog and it still tab switches the old way.

SVN Version 6196 on Ubuntu 9.10 32Bit

Any idea's??? :)
Title: Re: Improvement in TabSwitcher
Post by: Alatar on March 28, 2010, 11:19:01 am
Hmm... No idea`s... Please contact me by PM.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on June 09, 2010, 12:09:32 am
Ne informations about this path ?
richarduk, you finally make it works ? What was the problem ?
Thanks to give news back...
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on September 23, 2010, 03:09:59 pm
It seems it have been accepted, isn't it ? What does it mean ?
It is present into the last release ? -> No, it is not present in new release... What this patch need to be integrated ? I can't use Code::Blocks as this without this patch, the editor is awful to use when switching between differents sources...
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 06, 2011, 12:36:24 pm
No more news ?
If I apply this patch now, it makes conflicts....
Title: Re: Improvement in TabSwitcher
Post by: MortenMacFly on January 06, 2011, 08:59:25 pm
No more news ?
If I apply this patch now, it makes conflicts....
It is applied in trunk. Why would you want to apply it again? This surely results in conflicts.
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 07, 2011, 01:51:31 pm
I saw it was accepted but after the last release (10.5). I'm trying to compile wxWidgets + CodeBlocks from svn but last MinGW (gcc compiler) is not stable, it crash when compiling wxWidgets 2.8.11, so I have not seen the last codeblocks svn trunk look.
I just test to appy patch to see if the patch was really accepted... ok it was, sorry for this question...
I'm really happy that this patch is accepted, I have made a little contribution for this patch that is really cool !
Have an happy new year !
Title: Re: Improvement in TabSwitcher
Post by: oBFusCATed on January 07, 2011, 02:26:44 pm
Why don't you use a nightly?
Title: Re: Improvement in TabSwitcher
Post by: Feneck91 on January 07, 2011, 03:40:19 pm
Because I had the way to make codeblocks from source code... Some Months ago I had to compile it to have this patch so I know how to compile it...
I never use the nightly build and I don't konw how to use it, I suppose it is really faster than compile all !!  :D
I'll try it...