• Welcome to Powerbasic Museum 2020-B.


Forum in repository mode. No new members allowed.

Main Menu

CSED - Modification

Started by Gary Beene, October 17, 2013, 02:31:56 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Gary Beene

I believe I'm done with the mods to CSED and would like a volunteer or two to take a look at it before I release it.  If you're interested, please let me know!  Send me a PM and I'll give you the download URL.

Gary Beene

Well, done isn't happening. The more I work with it, the more "tweaks" I'd like to try out!   :)

Gary Beene

Other than closing all files and then reopening them in a specified order, does MDI have a way to drag a file to a new TAB position? 

Dragging would be most convenient.

But, I could also add "Move Left", "Move Right" menus items to the TAB context menu that now has just "Close".  But that still means I'd have to close all, re-open all files.   uhhh ... no, the open/close is not right.  Swapping properties would be more appropriate. 

Can you suggest a better approach?

José Roca

The tabs have nothing to do with the MDI engine. I added them for convenience. Therefore, what you need to move is the tab. For that, you may need to save the information that it contains, delete it and recreate it at the new position.

Gary Beene

Jose, thanks for the response!  I'll give that a try.

QuoteThe tabs have nothing to do with the MDI engine

Even so, I assume there's a way to go from a TAB number to the corresponding MDI child window handle?

I would like to cycle through the open Files, in the order they are shown (left TAB to right TAB), gathering information about each one.   Like this ...
QuoteFor nTab = 1 To psed.TabFilePaths.Count    'alternate - TabCtrl_GetItemCount(pSed.hTabMdi)
      hMDI = ?
      vPath = AfxGetWindowText(hMdi)    'alternate - vPath = pTabFilePaths.Item(nTab+1)
      hSci = GetDlgItem(hMDI, %IDC_Edit)
      caretPos = SCI_GetCurrentPos(hSci)
   Next nTab
Is there a way to get the hMDI handle from a given TAB number?

José Roca

The only way to get the handles of the MDI child windows is to enumerate them. The tab control is completely alien to MDI and I implemented it only as a convenience for easily select a file instead of having to use the "Window" menu. I'm beginning to think that it was a bad idea, because apparently everybody is using the editor as a tabbed one instead of a MDI one. If you want to see MDI in action, then uncheck the "Maximize edit windows" option.

If you want an editor controlled by the tab control instead of by the MDI engine, then forget MDI and make a non-MDI tabbed editor like the PB one, where the edit controls are children of dialogs associated with the tab pages. Otherwise, don't mess with the tabs.

In the CSED_CLASSES.INC file there is remed code to get and save the caret positions. I remed it, because if there are many files open it causes flicker if you have the "Maximize edit windows" checked.

   ' =====================================================================================
   ' Note: This one allows to save the caret position.
   ' =====================================================================================
'   METHOD SaveFileSet
'      LOCAL i AS LONG
'      LOCAL idx AS LONG
'      LOCAL nCount AS LONG
'      LOCAL strIndex AS STRING
'      LOCAL strPath AS STRING
'      LOCAL hwndActive AS DWORD
'      LOCAL hMdi AS DWORD
'      LOCAL caretPos AS LONG
'      LOCAL strLine AS STRING
'      ' // Delete the section
'      IniFileDeleteSection(m_szIniFileName, "File set")
'      ' // Get the number of child MDI windows
'      nCount = 0
'      hMdi = GetWindow(pSed.hwndClient, %GW_CHILD)
'      DO WHILE hMdi <> 0
'         hMdi = GetWindow(hMdi, %GW_HWNDNEXT)
'         INCR nCount
'      LOOP
'      IF nCount = 0 THEN EXIT METHOD
'      ' // Add the paths of the files
'      hwndActive = MdiGetActive(pSed.hwndClient)
'      idx = 1
'      FOR i = 1 TO nCount
'         hwndActive = MdiGetActive(pSed.hwndClient)
'         strPath = Window_GetText(hwndActive)
'         caretPos = SCI_GetCurrentPos(pSed.hEdit)
'         IF (INSTR(strPath, ANY ":\/") <> 0) THEN
'            strLine = FORMAT$(caretPos, "000000") & "|" & strPath
'            strIndex = "File " & FORMAT$(idx)
'            AfxIniFileWrite m_szIniFileName, "File set", strIndex, strLine
'            INCR idx
'         END IF
'         MdiNext(pSed.hwndClient, hwndActive, 0)
'      NEXT
   ' =====================================================================================

BTW AfxGetWindowText(hMdi) does not need a variant, because what it returns is a string. vPath is used with pTabFilePaths.Item because it is a method of the PB's ILinkListCollection class.

Theo Gottwald

Jose, to me the Combination of MDI and TAB'ed has its own Charm.
Its good that you did it this way.

Patrice Terrier

In UltraEdit, i never used the MDI but always the TAB mode, and the same with VisualStudio.

By the way i use TAB in all my applications, and even TAB within TAB...  8)
Patrice Terrier
GDImage (advanced graphic addon)

Gary Beene

Howdy Jose!

Thanks for the information!
Quote...only way to get the handles of the MDI child windows is to enumerate them

That suggests you weren't expecting to access the open files from left to right, as listed in the TAB?  I can see ways to work around it, but that seems like something I'd do in code regularly.

I can think of a couple of workarounds, such as building a temporary array each time I want to walk through the TABs, DIM'd to TAB count, that contains the handle corresponding to each TAB. 

Or, I could just create a short function that enumerates through the handles until it finds the handle to the TAB of interest.  That's probably the most convenient thing to do.  Something like this ...

Function hMDIofTAB(TargetTAB As Long) As Dword
   Local vPath As Variant, hMDI As Dword, nTAB As Long
   hMDI = GetWindow(pSed.hwndClient, %GW_Child)
   While hMDI
      vPath = AfxGetWindowText(hMdi)                        'get path from the collection
      nTab = CSED_GetTabNumberFromPath(Variant$$(vPath))    'get TAB number from Path
      If nTab = TargetTAB Then Function = hMDI : Exit Function
      hMDI = GetWindow(hMDI, %GW_HWNDNEXT)
End Function

Even better would be to use the code from CSED_GetTabNumberFromPath and make a function that doesn't have to call any other function.

José Roca

> That suggests you weren't expecting to access the open files from left to right, as listed in the TAB?

When you enumerate the MDI child windows, the returned handles don't come necessarily in the same order than the tabs.

Seeing all the confussion that are creating to you, if I ever write a new version I think that I will remove the tabs and display the opened files in the context menu. Tabbed or MDI, no more hybrids.

I wanted to incorporate some of the features of Lynx (this would made unneeded all that you're intending to do), but it has proven to be too difficult.

Gary Beene

Hi Jose!
QuoteSeeing all the confusion that are creating to you ...
I like the TABs just fine, as do users, I think. 

It was only when modifying the code that the MDI/TAB independence surprised me.  With translation functions like the one I just posted, it's easy enough to work with the TABs as I might have expected to be able to do. 

One of the benefits to me personally, of doing a mod to CSED,  was to see first-hand how you write code. Just because it's not the way I write doesn't deter me at all - hence the ongoing questions I've asked to get more comfortable with your code.  And I do appreciate you patience!

Gary Beene

I'm using .sed as my project file extension and have modified CSED to associate itself with that file extension. When I double click on a *.sed file, CSED opens up just fine, with the file loaded.  I can see that the file is fed to CSED on the command line.

But if CSED is already open, double-clicking on a *.sed file does not open the file.  I'm not seeing which message is sent with the additional file name.  I know you've built that into CSED because I can see it work. But I've not figured out what part of the code handles it.

Can you point me in the right direction?

Pierre Bellisle

Hey Gary,

See CSED_ProcessCommandLine sub in cSed.bas
and have a look at in what circonstances it is called... 


Gary Beene

Hi Pierre!
Nice to hear from you, and thanks for the direction ...

If I understand it right, CSED_ProcessCommandLine is called when there's already an instance of CSED running, yes?

I ran a quick test to confirm that, and that the double-clicked file is in Command$.

Although, I thought I had checked command$ and found it to be empty when a new file was double-clicked and the app was already open. I must have put my checking code in the wrong place. 

Thanks for the pointer. That should be get me going ....

José Roca

If I understand it right, CSED_ProcessCommandLine is called when there's already an instance of CSED running, yes?

CSED_ProcessCommandLine is called in all cases, unless the command line is empty.

If there is not a previous instance of CSED running or the option "Allow multiple instances" is checked, it posts a custom %WM_USER + 1000 message to delay the loading until other actions have been performed.

   ' // If the command line isn't empty post a message to process it later
   IF LEN(COMMAND$) THEN PostMessage hwndMain, %WM_USER + 1000, 0, 0

The code of the processing of that message is:

      CASE %WM_USER + 1000
         ' // Process the command line
         CSED_ProcessCommandLine hwnd

If there is an instance of CSED already running and the option "Allow multiple instances" is unchecked, it finds the window handle of the instance already running, sends a WM_COPYDATA message to it, and exits. This is performed in the SUB CSED_ProcessCommandLine procedure.

         ' // For Lynx support
         pDataToGet = lParam
         pszBuffer = @pDataToGet.lpData
         CSED_OpenFile TRIM$(@pszBuffer)
         SCI_GotoLine(pSed.hEdit, SCI_GetTextLength(pSed.hEdit))
         SCI_GotoLine(pSed.hEdit, @pDataToGet.dwData)

Although the comment says "For Lynx support", it is valid for any other application. Besides the file, you can also specify the line number.

WM_COPYDATA is used to pass data to another application. In this case, to pass information from the second instance of CSED that is going to be aborted to the already running instance of CSED.


WM_COPY DATA message

Using Data Copy