Powerbasic Museum 2020-B

Webmaster: José Roca (PBWIN 10+/PBCC 6+) (SDK Forum) => CSED Editor => Topic started by: Gary Beene on October 17, 2013, 02:31:56 AM

Title: CSED - Modification
Post by: Gary Beene on October 17, 2013, 02:31:56 AM
I was looking at CSED and wanted to see if I could modify it highlight the name of a function/method, then have CSED jump to that function/method - regardless of which file/TAB it is in.  Perhaps a context menu with "GoTo Function Under Cursor", or something like that.   I don't see that feature  right now.

Has anyone already done a mod like that?

Doesn't seem like it would be terribly hard, but it's always best to see if the job's already been done!
Title: Re: CSED - Modification
Post by: José Roca on October 17, 2013, 03:46:47 AM
I remember that I implemented it in the old SED editor. There was also a shortcut key to go back. That editor had more features than CSED, but as it was my first SDK application it was not as well structured as CSED. Besides, there were apportations of several people that later left the project and was a nightmare to me to update the code with each new version of PB. I write CSED from scratch and decided to implement only the features that I use and allow others to use it to make their own versions if they wish.

I also used CSED to test my CWindows class and wrappers and the beta versions of the new compilers. It was the first PB application to be fully unicode and High DPI aware.
Title: Re: CSED - Modification
Post by: Gary Beene on October 17, 2013, 04:26:41 PM
Jose,
I downloaded v1.03 (that's the latest, yes) and tried to compile with PBWin10.

This line fails (line #963 in CSED.bas):
If hwndClient Then AfxShowFileProperties(hwnd, AfxGetWindowText(MdiGetActive(hwndClient))), %TRUE)

Looking at your afxshell.inc file, the AfxShowFileProperties requires only 2 arguments, but you have 3 in the CSED.bas code.

It looks like the %True show be removed. Is that true?
Title: Re: CSED - Modification
Post by: Pierre Bellisle on October 17, 2013, 04:48:36 PM
Hey Gary,

I got this...

••• CSED103_Source\CSED.BAS
IF hwndClient THEN AfxShowFileProperties(hwnd, AfxGetWindowText(MdiGetActive(hwndClient)), %TRUE)

••• José\Windows API Headers\2.05\AfxShell.inc
FUNCTION AfxShowFileProperties (BYVAL hwnd AS DWORD, BYREF wszFileName AS WSTRINGZ, OPTIONAL BYVAL bDisplayError AS LONG) AS LONG

••• José\Windows API Headers\3.1.0.4\AfxShell.inc
FUNCTION AfxShowFileProperties (BYVAL hwnd AS DWORD, BYREF wszFileName AS WSTRINGZ) AS LONG

So I guess it's true that %true should be thrown away...   ;D
Title: Re: CSED - Modification
Post by: Gary Beene on October 17, 2013, 05:03:57 PM
Howdy Pierre!
Always good to hear from you!

I compiled it successfully without the %TRUE. I'll watch for any obnoxious behaviour.  But based on what 2.05 says it was for, looks like its a no-impact change!
Title: Re: CSED - Modification
Post by: Pierre Bellisle on October 17, 2013, 05:52:45 PM
According to 2.05 this was a flag to generate a messagebox in case of a ShellExecuteEx error,
like "File not found", "Path not found", "Access denied", etc.

So, no big deal I guess....

Pierre

Title: Re: CSED - Modification
Post by: José Roca on October 17, 2013, 05:53:20 PM
There are not side effects. Just remove the %TRUE parameter.
Title: Re: CSED - Modification
Post by: Theo Gottwald on October 17, 2013, 11:11:25 PM
Gary, there are a few more bits that you can change in CSED.
I remember that i changed a setting that influences the quality of the font-drawing.
Possibly Jose remembers the exact parameters. It had to do with the scintilla control.

Title: Re: CSED - Modification
Post by: José Roca on October 17, 2013, 11:47:20 PM
In the file CSED_SCI.INC, after


' ========================================================================================
' Set Scintilla Edit Control's options
' ========================================================================================
SUB CSED_SetScintillaOptions (BYVAL hSci AS DWORD, BYVAL strFileExt AS STRING)

   LOCAL bitsNeeded AS LONG   ' // Number of bits needed by the lexer for styling

   ' // Get direct pointer for faster access
   LOCAL pSci AS DWORD   ' // Scintilla's direct pointer
   pSci = SCI_GetDirectPointer(hSci)
   IF pSci = 0 THEN EXIT SUB



add


   ' // If Vista/Windows 7, use Direct Write for higher quality antialiased drawing
   IF AfxGetWindowsVersion => 6 THEN
      SCIP_SetBufferedDraw(pSci, 0)
      SCIP_SetTechnology(pSci, %SC_TECHNOLOGY_DIRECTWRITE)
   END IF


But you need to download the latest version of SciLexer.dll. Older versions were buggy and it did not worked.
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 01:37:40 AM
I've completed the mod (well, still testing, but good so far). Other than some code to add a new context menu, "Find Procedure", I was able to keep the change down to a single function which I placed in csed.bas

User action is like this:
1. Highlight text (a function/sub/method/fastproc name)
2. Right click and select a new context menu item , "Find Procedure"
3. Click the menu item to search open files for a procedure by the name of the selected text
4. If found, matching TAB/text is selected/highlighted. Document scrolls to the matching procedure.
5. If not found, a MsgBox pops up with "Procedure NOT found ..." + selectedtext

There's no Find Next - I assume there's only one procedure by the selected name.

Here's the function I added. It's called when the context menu is selected. I pulled the basic enumeration code from CSED_TabCtrl.INC, then added the search lines from some code I already had on hand.

Jose, the pSed.hEdit values seems to get updated by the enumeration code (MDIActive, I'd guess). Is that right?

If there's any obvious problem with this code being compatible with the rest of the CSED code, please let me know! 

Sub LocateProcedure_BEENE(temp$)        'temp$ is highlighted text
   Local i,j,iResult,nTAB As Long, hMDI As Dword
   Local vPath As Variant, tmp$, FindStructure As SCI_TextToFind

   'strings to look for--------------------------------
   tmp$ = LTrim$(LCase$(temp$))
   Dim target(6) As StringZ * 65
   target(0) = "sub " + tmp$               : target(1) = "function " + tmp$
   target(2) = "static sub " + tmp$        : target(3) = "static function " + tmp$
   target(4) = "callback function " + tmp$ : target(5) = "fastproc function " + tmp$
   target(6) = "method " + tmp$

   'enumerate Edit windows-----------------------------
   AfxDisableWindowRedraw pSed.hwndClient                   'disable redraw
   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
      TabCtrl_SetCurSel(pSed.hTabMdi, nTab)                 'select the TAB
      MDIActivate(pSed.hwndClient, hMdi)                    'activate this MDI child window
      '---highlight search string, if found, in newly activated TAB edit control ----------
         For j = 0 To UBound(target)
            FindStructure.Chrg.cpMin = 0
            FindStructure.Chrg.cpMax = SendMessage(pSed.hEdit,%SCI_GetLength,0,0)
            FindStructure.lpstrText = VarPtr(target(j))
            iResult = SendMessage (pSed.hEdit, %SCI_FindText, 0, VarPtr(FindStructure))
            If iResult > -1 Then
               SendMessage pSed.hEdit, %SCI_SetSel, FindStructure.ChrgText.cpMin, FindStructure.ChrgText.cpMax
               AfxEnableWindowRedraw pSed.hwndClient        'enable redraw
               If pSed.hEdit Then RedrawWindow pSed.hEdit, ByVal %NULL, %NULL, %RDW_ERASE Or %RDW_FRAME Or %RDW_INVALIDATE
               Exit Loop
            End If
         Next j
      '-----------------------------------------------------------------
      hMDI = GetWindow(hMDI, %GW_HWNDNEXT)
   Wend
   If iResult = - 1 Then MsgBox "Procedure NOT found ...  " + tmp$, %MB_Ok + %MB_IconExclamation, "Search for Procedure"
End Sub

Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 01:49:16 AM
When you call pSed.hEdit, you always get the handle of the active scintilla control, because it does not return you an stored value, but is a property that retrieves it by calling GetDlgItem(MdiGetActive(m_hwndClient), %IDC_EDIT).
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 03:59:07 AM
Jose,
Thanks for that explanation. Now that you describe where hEdit comes from, I can see that in your code.

It occurred to me that there should be a simpler way to enumerate the TABs/Scintilla controls than what I used up above, one that doesn't require the use of the vpath approach.

This snippet is what I'm thinking ...
   TABCount = SendMessage(pSed.hTabMdi, %TCM_GetItemCount,0,0)
   For i = 0 To TabCount
      TabCtrl_SetCurSel(pSed.hTabMdi, i)       'select the TAB
      hMDI = ?????                             '<---- how to get hMDI of i-th TAB
      MDIActivate(pSed.hwndClient, hMdi)       'activate this MDI child window
      '--- search/highlight code goes here
   Next i

But I haven't been able to figure out the line that gets the hMDI value in each pass of the loop.  Would you point me in the right direction? 
Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 05:52:21 AM
I'm afraid not. The scintilla controls are not children of the tab controls. Therefore, selecting a tab does not activate any window. To get hMdi you have to call MdiGetActive, but as the active window has not changed, you will always get the same handle (the one of the last activated MDI child window) no mather of which tab you select.
Title: Re: CSED - Modification
Post by: Paul Squires on October 18, 2013, 01:03:06 PM
Just a suggestion:
Instead of highlighting the text and then selecting from a menu to search for the procedure, try getting the word at the current cursor position and then select the find procedure from the menu. Eliminating the need to highlight the word first is common in most editors/IDE's.
Title: Re: CSED - Modification
Post by: Aslan Babakhanov on October 18, 2013, 01:51:56 PM
BTW, this option is available in QB (4.5, 7.1) ide's. You just move cursor to the sub/function name and pressing F2, then immediately getting in to the list of subroutines with highlighted function/sub. You only need to press ENTER key to jump. If I'm not mistaken, that worked even with included files. Say you have main.bas and two included files incl1.inc and incl2.inc. Function AAA placed in incl2.inc file and called from main.bas. You move cursor to AAA sub in main.bas and pressing F2 - Ide immediately showing the list of all subs and moving cursor to the AAA sub in incl2.inc file... Pretty easy and helpful, if you want to tap onto desired sub right from cursor, without touching the mouse.
Title: Re: CSED - Modification
Post by: Paul Squires on October 18, 2013, 03:29:20 PM
This works with FireFly Visual Designer and JellyFish Pro Editor as well. Press F6 while caret positioned over function name to take you to that function. Press Shift+F6 to return back.
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 04:36:47 PM
Hey Paul!
Thanks for the suggestion ...
QuoteInstead of highlighting the text...
I'd though of that, but sometimes in my apps I have functions like MyTasks and MyTask, where the first calls the second repeatedly. So I wanted the option to highlight only the MyTask part of MyTasks.  Not exactly a strong case for highlighting, but it was the thought that drove my approach.

But, you bring up a perspective I wasn't thinking about - using the keyboard.   Not that I can't use the keyboard to highlight a sequence of strings, but I like the idea of your F6 - simpler to use 'cause there's no highlighting by keyboard required.
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 05:20:50 PM
Where is the code that changes the caption of the CSED main window, when a new file is opened?

I search for $CSEDVERSION, $CSEDCAPTION, and even the [ symbol. 

I found AfxSetWIndowText used on the TABs, but not on the main window caption.

Nor do I see it in the CSED_OpenFile procedure.

I even made a temp file containing every include/bas file in CSED, searching that way instead of guessing which include might have contained the right code.

Would someone point me in the right direction?  And please, don't let it be really obvious!  :)
Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 05:55:29 PM
Be patient. You're new to MDI. The caption that is changed is not the caption of the main window, but the caption of the MDI window. You must be running the editor with the option to maximize MDI child windows activated and you're only seeing the tabs. See the capture below and you will see that the caption of the main window only has CSED and the version number and that each MDI window has as the caption the path of the loaded file.

The captions of the MDI child windows are changed in a couple of places: one in the CSED_OpenFile function of CSED_FILE.INC. This function first checks if the file is already loaded by enumerating the MDI child windows; if it is not, it calls the CSED_CreateMdiChild function, that creates a new MDI child window using the path of the file as the caption. Another place is in the CSED_SaveFile funcion, where it uses IF hMdi THEN AfxSetWindowText hMdi, strPath.
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 06:04:20 PM
Thanks Jose,
QuoteYou're new to MDI.
Yes, and I'm glad the text assignment was as you described rather than some trivial thing, such as having overlooked a few lines of code.

As you surmised, I did have the child windows maximized.
Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 06:11:04 PM
The menu has an item called "Window" with several MDI related options, such cascade, tile horizontal, tile vertical and Arrange icons, because MDI windows can be cascaded, tiled or iconized. besides maximized. It also keeps a list of the files loaded.

The tab control is foreign to MDI and only is being used by convenience. But selecting a tab does nothing else that highlight that tab, because it has not child controls,  and send you a message indicating that the user has changed the selection.

Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 06:31:17 PM
If windows are cascaded or tiled, you can select them by clicking in any part of them, e.g. the caption. See a capture with the windows cascaded.
Title: Re: CSED - Modification
Post by: Paul Squires on October 18, 2013, 08:12:04 PM
I believe the general trend is away from true MDI applications. The introduction of TAB controls to faciliate the switching amongst child windows makes it very easy to deal with multiple document layouts. In my personal experience, I have not had a burning need to create a true MDI application for over 10 years. I find that SDI applications and TAB'd child forms are much easier to implement and maintain. Of course, there will always be those situations where MDI is better (and I would argue only marginally), but for the vast majority of time you can get by without it.
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 08:36:29 PM
Jose,
A trivial question on a couple of lines of code I saw in CSED ...

Why did you do this (create an extra variable) ...
   Local hwndClient As Dword
   hwndClient = pWindow.CreateMDIWindow(101, 0, 0, 0, 0, -1, -1, hWindowMenu, CodePtr(CSED_MDIWindowProc))
   pSed.hwndClient = hwndClient


Instead of this:
   pSed.hwndClient = pWindow.CreateMDIWindow(101, 0, 0, 0, 0, -1, -1, hWindowMenu, CodePtr(CSED_MDIWindowProc))
Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 09:46:35 PM
It's hard to remember. As I said, one of the main purposes for which I wrote this editor was to test the beta versions of the compiler, and my headers and clases, with non trivial code. Of course, the beta versions of the compiler had bugs that this application helped me to discover. Probably, when I wrote these lines, there was a bug that didn't allowed to do the assignment directly, and later I forgot to change it. As you can see, the code uses many of the new features of PB 10, such classes, unicode, collections, linked lists... Many times I had to use workarounds until the bug was fixed.
Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 09:58:01 PM
I also used #IF DEFs to test that it worked either using ANSI or UNICODE. Currently, all my applications are unicode only.
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 10:32:05 PM
Jose,
When I run this short code, taken from your CSED source code files, my modified version of CSED starts alternately highlighting the TAB that is active when the code begins and the last TAB on the right. The program never leaves the loop, freezes up and I have to close the program to stop the flickering.

It seems to be identical to code you've used several times in CSED, but I'm getting unexpected result.

   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
      TabCtrl_SetCurSel(pSed.hTabMdi, nTab)                 'select the TAB
      MDIActivate(pSed.hwndClient, hMdi)                    'activate this MDI child window
      hMDI = GetWindow(hMDI, %GW_HWNDNEXT)
   Wend

Am I doing something obviously wrong?
Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 11:03:01 PM
Debugging .... I find that if I test the nTab value each loop, it alternates between 0 and 2 (when I have 3 files opened).  Don't know why it's skipping the nTAB=1 value.

The hMDI value likewise alternates between 2 values, not three.
Title: Re: CSED - Modification
Post by: José Roca on October 18, 2013, 11:14:13 PM
I don't understand which is the puporse of that code. After vPath = AfxGetWindowText(hMdi) one should check if it is the window wanted, activate it and leave the loop, e.g.:


hMDI = GetWindow(pSed.hwndClient, %GW_Child)
While hMDI
   vPath = AfxGetWindowText(hMdi)                        'get path from the collection
   IF VARIANT$$(vPath) = "<something>" THEN
      nTab = CSED_GetTabNumberFromPath(Variant$$(vPath))    'get TAB number from Path
      TabCtrl_SetCurSel(pSed.hTabMdi, nTab)                 'select the TAB
      MDIActivate(pSed.hwndClient, hMdi)                    'activate this MDI child window
      EXIT DO
   END IF
   hMDI = GetWindow(hMDI, %GW_HWNDNEXT)
Wend

Title: Re: CSED - Modification
Post by: Gary Beene on October 18, 2013, 11:29:05 PM
Hi Jose, and thanks for responding!

I posted the full function back up in post #9.  That code contains an exit strategy, as you suggest, which is to exit when the scintilla control associated with the TAB has a procedure of a given name.  That code seemed to be working, but is now showing the problem I described.

I pared the post #9 code down to just the few lines above, just to show which code is giving the problem.

The loop, without an exit function strategy, should end on its own. It should walk sequentially through tab numbers 0-2 (when I have 3 files open in CSED). But it does not. It walks repeatedly between tabs 0 and 2 - and I don't see why it is doing that.
Title: Re: CSED - Modification
Post by: Gary Beene on October 19, 2013, 12:02:09 AM
Well, there's an interaction of some kind going on ... something I've apparently not understood ...

This code correctly ends on it's own, after identifying the 3 available values of hMDI:

   hMDI = GetWindow(pSed.hwndClient, %GW_Child)
   While hMDI
      hMDI = GetWindow(hMDI, %GW_HWNDNEXT)                  'get next TAB
   Wend


One or more of the other lines in this failing example is messing with the hMDI loop value, perhaps?
   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
      TabCtrl_SetCurSel(pSed.hTabMdi, nTab)                 'select the TAB
      MDIActivate(pSed.hwndClient, hMdi)                    'activate this MDI child window
      hMDI = GetWindow(hMDI, %GW_HWNDNEXT)
   Wend

The chase is afoot!
Title: Re: CSED - Modification
Post by: Gary Beene on October 19, 2013, 12:10:01 AM
Just by eliminating lines, this lnext line seems to be the culprit!  When removed, the loop ends as expected.

MDIActivate(pSed.hwndClient, hMdi)                    'activate this MDI child window

I thought, by activating the TAB corresponding to hMDI, that the corresponding Scintilla Control would become active and be reported by pSed.hEdit (I need the Scintilla control handle in order to search its text content)

But it seems that the activation also messes with hMDI?  I'll go look at Jose's code for the MDIActivate function.

(sorry if it seems like I'm talking to myself here.  Just thinking through the process ...)
Title: Re: CSED - Modification
Post by: Gary Beene on October 19, 2013, 12:28:43 AM
So, if MDIActivate cannot be used in the loop, I guess I need another approach to making the scintilla control active (corresponding to nTAB or vPath in the loop) so I can access it using pSed.hEdit.
Title: Re: CSED - Modification
Post by: José Roca on October 19, 2013, 01:14:02 AM
You don't need to activate the MDI window or use pSed.hEdit to access the scintilla control. As you have the handle of the MDI window (hMdi) you can just use hSciCtrl = GetDlgItem(hMdi, %IDC_EDIT) to get the handle of the control, do the search and, if found, then activate the MDI window, select the associated tab and leave the loop.
Title: Re: CSED - Modification
Post by: José Roca on October 19, 2013, 01:31:25 AM
Someting like this:


LOCAL hSciCtrl AS DWORD
hMDI = GetWindow(pSed.hwndClient, %GW_Child)
While hMDI
   hSciCtrl = GetDlgItem(hMdi, %IDC_EDIT)
   IF hSciCtrl THEN
      ' Do the search
      ' ---
      ' IF found...
      vPath = AfxGetWindowText(hMdi)
      nTab = CSED_GetTabNumberFromPath(Variant$$(vPath))
      TabCtrl_SetCurSel(pSed.hTabMdi, nTab)
      MDIActivate(pSed.hwndClient, hMdi)
      EXIT DO
   END IF
   hMDI = GetWindow(hMDI, %GW_HWNDNEXT)
Wend


BTW instead of vPath you can use an STRING if ansi is enabled or a WSTRING if unicode is enabled.


#IF %DEF(%UNICODE)
   LOCAL strPath AS WSTRING
#ELSE
   LOCAL strPath AS STRING
#ENDIF
LOCAL hSciCtrl AS DWORD
hMDI = GetWindow(pSed.hwndClient, %GW_Child)
While hMDI
   hSciCtrl = GetDlgItem(hMdi, %IDC_EDIT)
   IF hSciCtrl THEN
      ' Do the search
      ' ---
      ' IF found...
      strPath = AfxGetWindowText(hMdi)
      nTab = CSED_GetTabNumberFromPath(strPath)
      TabCtrl_SetCurSel(pSed.hTabMdi, nTab)
      MDIActivate(pSed.hwndClient, hMdi)
      EXIT DO
   END IF
   hMDI = GetWindow(hMDI, %GW_HWNDNEXT)
Wend

Title: Re: CSED - Modification
Post by: Gary Beene on October 29, 2013, 02:24:37 PM
Jose,
I want to include the Project Name (in the mod I'm working), along with the currently selected file nam,  in the main window caption.  Can you point me to the section of code that changes the caption?

I've found all instances of SetWindowText, but as best I can tell, none affect the main window.

I also searched for all instances of $PROGNAME, $CDSEVERSION and $CSEDCAPTION. But likewise, none of these helped me locate the caption changing code.

I also tried tracing File New and tracing a click on the a tab, but still I don't see where the caption is changed!

Surely it's right under my nose, but I'll be darned if I can see it!
Title: Re: CSED - Modification
Post by: José Roca on October 29, 2013, 03:36:59 PM
In the line 168 of CSED.BAS, the content of the constant $CSEDCAPTION is used as the title of the main window.


   hwndMain = pWindow.CreateWindow(%NULL, $CSEDCAPTION, _
              0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top, -1, -1, CODEPTR(CSED_WindowProc), %TRUE)

Title: Re: CSED - Modification
Post by: Gary Beene on October 29, 2013, 03:47:20 PM
Hi Jose,
Yes, thank you, I found that.

But when a new file is opened, the caption is changed from $CSEDCAPTION to include the new file name.  That's what I don't find - where the caption is modified during execution of the program.
Title: Re: CSED - Modification
Post by: Gary Beene on October 29, 2013, 03:55:36 PM
Perhaps this is one of those MDI features, where you only specify the file path and the MDI code adds that to the window caption?

I was expecting something like ... $CDSECAPTION + strPath ... where the code specifies the entire caption.

Instead perhaps an MDI statement only requires the strPath and it adds that to the caption without your code explicitly having to use the term $CSEDCAPTION in the code? 

I'll go see if that thought helps me ....
Title: Re: CSED - Modification
Post by: José Roca on October 29, 2013, 04:40:31 PM
Please, reread the reply #18. You must try the editor with the "Maximize edit windows" unchecked.

Each MDI window has its own caption, independent of the main window's caption. When you maximize the MDI window, Windows merges its caption with the one of the main window, making it to appear as if there is only one caption, but there are two. I never change the main window's title, only the one of the MDI windows. And I only use the path as a way to easily retrieve it without having to use, for example, a global array of paths (I always try to avoid to use globals, you know).
Title: Re: CSED - Modification
Post by: Gary Beene on October 30, 2013, 04:23:23 AM
Jose!
When I finish the CSED mods I'm working on, what's the protocol for releasing the modified version of CSED, and the source code to go with it?   

I see your copyright statements in the source code files, so I want to make sure I follow your requirements for releasing any modifications I come up with.
Title: Re: CSED - Modification
Post by: José Roca on October 30, 2013, 05:42:11 AM
Just made it available, here or elsewhere, it does not matter. As stated in the CSED thread:

Permission is granted to develop new versions of the editor as long as the source code is made freely available in this forum or elsewhere.
Title: Re: CSED - Modification
Post by: Gary Beene on October 30, 2013, 06:48:58 PM
Jose,
Just a general question about coding, regarding your code in CSED ...

In the window procedure you seem to always put EXIT FUNCTION after each Case option.  Is there ever a case where not putting in EXIT FUNCTION won't exit correctly?

In my apps, all code in DlgProc is found within Case options.  There's no code that will execute if EXIT FUNCTION is not explicitly used.  But since you use EXIT FUNCTION in every Case, I thought perhaps that means you are explicitly avoiding something? The question is what?
Title: Re: CSED - Modification
Post by: José Roca on October 30, 2013, 08:21:39 PM
SDK callbacks don't work exactly as DDT callbacks. Exiting the function when the message has been processed avoids the call to DefWindowProc (if it is a message for the main window) or DefFrameProc (if it is a message for the MDI client window).

MDI applications are more complicated that the non-MDI ones. Besides DefWindowProc and DefFrameProc, there is also DefMDIChildProc, which processes messages for MDI child windows.

In a non MDI SDK application, I use FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam) as the last line of the function, after the SELECT CASE block. Therefore, if EXIT FUNCTION isn't used, the call to DefWindowProc is executed. DefWindowProc calls the default window procedure to provide default processing for any window messages that an application does not process. This function ensures that every message is processed. So EXIT FUNCTION must be used when you have processed the message and you don't want that the system will execute any default action.

For example, to avoid flicker, a SDK application often proccesses the WM_ERASEBKGND message and exits the function with a return value of 1. This prevents that Windows will erase the background and leaves the repainting to you.

EXIT FUNCTION is not used in all the procesed messages. Sometimes, you process the message to do something special and you also lets DefWindowProc to perform the default action.

With SDK you have full control. This means more power, but requires more knowledge.

There are also differences on how keyboard messages are processed depending if the message pump uses IsDialogMessage or not. In general, IsDialogMessage is used when the application has child controls such buttons, etc., and not used in graphic applications. You can find a good article about message pumps in the PB Gazette #38: http://www.powerbasic.com/support/downloads/gazette/gaz038.txt

Because of these and other differences, I avoid to mix the use of SDK for some applications and DDT for others, because it is easy to make mistakes. I wrote the CWindow class to simplify GUI programming, as DDT does, but still is SDK, meaning that there are no differences in the processing of the messages.
Title: Re: CSED - Modification
Post by: Gary Beene on October 31, 2013, 08:28:53 PM
Thanks, Jose, for the information.  Even if I'm not writing in SDK, I'm still interested in learning more about it and will likely write some apps with it just for the experience, if nothing else.  But what I really am interested in, with SDK, are app demonstrations which cannot be done without SDK.  I know I've mentioned the idea in another thread, and will pursue it more next week.

Regarding CSED ...

I've got my mod (projects support and search for procedures, including searching unloaded source code files in project file folder) to CSED up and running. I'm just doing testing on it right now.  I hope to have it out in within the week.  I appreciate the help you've given in getting me past a few sticking points with SDK and MDI.
Title: Re: CSED - Modification
Post by: Gary Beene on November 01, 2013, 07:08:33 PM
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.
Title: Re: CSED - Modification
Post by: Gary Beene on November 04, 2013, 09:00:42 PM
Well, done isn't happening. The more I work with it, the more "tweaks" I'd like to try out!   :)
Title: Re: CSED - Modification
Post by: Gary Beene on November 04, 2013, 09:35:59 PM
Jose,
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?


Title: Re: CSED - Modification
Post by: José Roca on November 04, 2013, 10:12:59 PM
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.
Title: Re: CSED - Modification
Post by: Gary Beene on November 05, 2013, 04:35:06 AM
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?
Title: Re: CSED - Modification
Post by: José Roca on November 05, 2013, 06:00:04 AM
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
'      LOCAL vPath AS VARIANT
'      ' // 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
'   END METHOD
   ' =====================================================================================


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.

Title: Re: CSED - Modification
Post by: Theo Gottwald on November 05, 2013, 07:15:34 AM
Jose, to me the Combination of MDI and TAB'ed has its own Charm.
Its good that you did it this way.
Title: Re: CSED - Modification
Post by: Patrice Terrier on November 05, 2013, 10:23:25 AM
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)
Title: Re: CSED - Modification
Post by: Gary Beene on November 05, 2013, 03:20:17 PM
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)
   Wend
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.



Title: Re: CSED - Modification
Post by: José Roca on November 05, 2013, 10:04:52 PM
> 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.
Title: Re: CSED - Modification
Post by: Gary Beene on November 05, 2013, 10:37:02 PM
Hi Jose!
Re:
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!
Title: Re: CSED - Modification
Post by: Gary Beene on November 06, 2013, 12:06:08 AM
Jose,
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?
Title: Re: CSED - Modification
Post by: Pierre Bellisle on November 06, 2013, 01:23:33 AM
Hey Gary,

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

Pierre
Title: Re: CSED - Modification
Post by: Gary Beene on November 06, 2013, 01:42:52 AM
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 ....
Title: Re: CSED - Modification
Post by: José Roca on November 06, 2013, 03:45:02 AM
Quote
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
         EXIT FUNCTION


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.


      CASE %WM_COPYDATA
         ' // 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.

See:

WM_COPY DATA message
http://msdn.microsoft.com/en-us/library/windows/desktop/ms649011%28v=vs.85%29.aspx

Using Data Copy
http://msdn.microsoft.com/en-us/library/windows/desktop/ms649009%28v=vs.85%29.aspx
Title: Re: CSED - Modification
Post by: José Roca on November 06, 2013, 04:35:47 AM
Quote
One of the benefits to me personally, of doing a mod to CSED,  was to see first-hand how you write code.

This application is a little special. As I wrote it to test my CWindow class and wrappers, and the beta compilers (first version 9 and later version 10) with non trivial code, it makes use of many of the features implemented in these compilers, such classes, collections, queues, linked lists, string builder. First it was only ANSI, and during the beta testing of version 10, I added #IF DEFs to test that it worked fime both compiling it as ANSI or UNICODE. There are some left overs, like:


   '      vPath = pSed.TabFilePaths.Next
         pTabFilePaths = pSed.TabFilePaths
         vPath = pTabFilePaths.Next


The reason is that vPath = pSed.TabFilePaths.Next did not worked at that time because of a compiler's bug using the compound syntax and had to use an intermediate step. Later, probably I forgot to change it.

A remark saying that "we can't use the class name because all the CWindow main windows share the same class name." is no longer true, because I added an optional method to CWindow to specify the class name before you call the CreateWindow method.

I wrote CWindow to simplify SDK GUI creation, as the most often used objection against SDK was the many lines of code needed to fill the members of the WNDCLASSEX structure and register the class, the message pump and the many parameters of CreateWindowEx.

With CWindow, all that verbosity is reduced to:


pWindow.CreateWindow(%NULL, "CWindow with a button", 10, 10, 500, 320, 0, 0, CODEPTR(WindowProc))
pWindow.AddButton(pWindow.hwnd, %IDCANCEL, "&Close", 350, 250, 75, 23)
pWindow.DoEvents(nCmdShow)


And subclassing of a control is as easy as adding the address of the subclass procedure:


pWindow.AddButton(pWindow.hwnd, %IDCANCEL, "&Close", 350, 250, 75, 23, 0, 0, CODEPTR(TextBtn_SubclassProc))



' ========================================================================================
' Processes messages for the subclassed Button window.
' ========================================================================================
FUNCTION TextBtn_SubclassProc ( _
   BYVAL hwnd   AS DWORD, _                 ' // Control window handle
   BYVAL uMsg   AS DWORD, _                 ' // Type of message
   BYVAL wParam AS DWORD, _                 ' // First message parameter
   BYVAL lParam AS LONG _                   ' // Second message parameter
   ) AS LONG

   ' // REQUIRED: Get the address of the original window procedure
   LOCAL pOldWndProc AS DWORD
   pOldWndProc = GetProp(hwnd, "OLDWNDPROC")

   SELECT CASE uMsg
      CASE %WM_DESTROY
         ' // REQUIRED: Remove control subclassing
         SetWindowLong hwnd, %GWL_WNDPROC, RemoveProp(hwnd, "OLDWNDPROC")
   END SELECT

   FUNCTION = CallWindowProc(pOldWndProc, hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


When I did buy an high resolution monitor, I also added High DPI awareness to CWindow. The difference in sharpness is noticeable.
Title: Re: CSED - Modification
Post by: Gary Beene on November 06, 2013, 05:26:07 AM
Jose,
Thanks very much for the additional information.

Before your explanation I did not realize that all non-empty command line content is sent to WM_CopyData, regardless of whether the app is starting or whether a 2nd instance of the app is attempting to start (that is, when 2nd instances are not allowed).

In the case of an app startup, the initialization stuff occurs, then you POST WM_User+1000, which in turn calls ProcessCommandLine which in turn sends command line data to WM_CopyData for actual opening/adding of the file specified in the command line.

And in the case of a 2nd instance, startup/POST is skipped and you go straight to ProcessCommandLine which in turn sends command line data to WM_CopyData for opening/adding of the file specified in the command line.

That's a very interesting sequence, one that I had a time following until you gave your additional comments.  But helped by your comments, I've been able to write the code to double-click and load a project file, even if CSED is already open.
Title: Re: CSED - Modification
Post by: Gary Beene on November 06, 2013, 04:17:14 PM
Jose,
Just wandering around your CSED code some ....

In the Method FindOrReplace, when the dialog is already opened and the user hits Ctl-F again, you require that the user cancel the previous Find dialog.

You might, for example, have just kept the dialog open and replaced the search text with whatever the user now has highlighted.  Or, you might have had an Ok/Cancel on the popup MsgBox.  Or, you might just have automatically cancelled it yourself.

Can you comment on the thought process of taking the approach you did?
Title: Re: CSED - Modification
Post by: José Roca on November 06, 2013, 04:52:07 PM
The class stores the last search in the instance variable m_szLastFind to allow to do a next find (pressing the F3 key) or a backwards find (Shift+F3) without using the Find dialog. Obviously, if a second instance is allowed, the content of that variable will change, making useless to have the first instance of the dialog active.
Title: Re: CSED - Modification
Post by: Gary Beene on November 06, 2013, 05:04:53 PM
Hey Jose!
I wasn't so much thinking about having a 2nd Find dialog, as I was wondering why you didn't just automatically delete the first?

I guess that brings up the question. If I wanted to automatically close the first Find dialog and let a new one be created, how would I go about it?
Title: Re: CSED - Modification
Post by: José Roca on November 06, 2013, 05:36:23 PM
I'm using the Find/Replace dialog provided by Windows, not a custom dialog. It involves the registering of a custom message and special processing in the the message pump. The only safe way would be to find the handle of the Find dialog (you can't use the caption, because it is localized) and send a WM_CLOSE to it (or maybe to retrieve the identifier of the Cancel button and send a message to simulate a button click). Then send a WM_COMMAND message to the main window callback with the %IDM_FIND or %IDM_REPLACE identifier.

I think that is much simpler just to press the ESC key, but to each his own.

Title: Re: CSED - Modification
Post by: Gary Beene on November 07, 2013, 05:38:43 AM
Jose,
In my modifications to CSED, I've somehow caused the top and bottom toolbar to force all buttons to the same width - much wider than the image that they contain.  I've made no changes to the CSED_TOOLBARS.inc file.

(http://www.garybeene.com/images/pb_0756.jpg)
( toolbar buttons same size, too big )

I've searched through all the CSED source files, looking for where "toolbar" was used, but found nothing that I recognized as having the ability to force all toolbar buttons the same size.

Can you suggest where in your code I might have unknowingly resized the toolbar buttons?
Title: Re: CSED - Modification
Post by: José Roca on November 07, 2013, 06:12:20 AM
Change


   hToolBar = pWindow.AddToolBar(pWindow.hwnd, %IDC_TOOLBAR, "", 0, 0, 0, 0, _
              %WS_CHILD OR %WS_VISIBLE OR %TBSTYLE_TOOLTIPS OR %TBSTYLE_FLAT OR _
              %TBSTYLE_LIST OR %TBSTYLE_TRANSPARENT)


to


   hToolBar = pWindow.AddToolBar(pWindow.hwnd, %IDC_TOOLBAR, "", 0, 0, 0, 0, _
              %WS_CHILD OR %WS_VISIBLE OR %TBSTYLE_TOOLTIPS OR %TBSTYLE_FLAT)

Title: Re: CSED - Modification
Post by: Gary Beene on November 07, 2013, 06:25:05 AM
Jose,
I went back to the download file I got from you, CSED103_Source.rar.  I unpacked that and compiled the CSED.BAS.  The resulting EXE has the wide buttons.  But the EXE you put in your CSED103.Release.rar file has the narrow buttons.

So, I gather the change you just now posted must have been an update sometime between the source and release file uploads?

I tried the change you sent and that does the trick.  Because the release EXE didn't have the narrow buttons, I was assuming that my code mods had caused the change.  I'm always happy when it's not something I did!

Thanks!
Title: Re: CSED - Modification
Post by: Gary Beene on November 07, 2013, 06:31:25 AM
And, for the bottom toolbar I made the similar change of code like this ...
   hBottomToolBar = pWindow.AddToolBar(pWindow.hwnd, %IDC_BOTTOMTOOLBAR, "", 0, 0, 0, 0, _
              %WS_Child Or %WS_Visible Or %CCS_NoResize Or %TbStyle_Tooltips Or %TbStyle_Flat Or _
              %TbStyle_List Or %TbStyle_Transparent)
to this ...
   hBottomToolBar = pWindow.AddToolBar(pWindow.hwnd, %IDC_BOTTOMTOOLBAR, "", 0, 0, 0, 0, _
              %WS_Child Or %WS_Visible Or %CCS_NoResize Or %TbStyle_Tooltips Or %TbStyle_Flat)     'BEENE
Title: Re: CSED - Modification
Post by: Gary Beene on November 07, 2013, 02:45:05 PM
Jon Eskdale send me his fix to this ...
Quote... automatically close the first Find dialog and let a new one be created
which is this line ...
      If m_fr.lCustData <> 0 Then SendMessage m_hFind, %WM_Close, 0, 0
Title: Re: CSED - Modification
Post by: José Roca on November 07, 2013, 04:18:03 PM
I had forgotten that the handle of the Find window was already available.
Title: Re: CSED - Modification
Post by: Gary Beene on November 11, 2013, 03:49:06 PM
Hey Paul,
Yep, I like that idea ...
Quote.. getting the word at the current cursor position