Attached is the latest source code. I have been working on the "Environment Options" dialogs. The options are also saved and restored from a configuration file.
Updated: June 7, 2016
Updated: June 7, 2016 (later that evening)
Remove the deletion of CWindow from the WM_DESTROY message and put it after DoEvents:
Function frmOptions_Show( ByVal hWndParent As HWnd, _
ByVal nCmdShow As Long = 0 _
) As Long
...
...
' Process Windows messages
Function = pWindow->DoEvents(nCmdShow)
' // Destroy the CWindow class
Delete pWindow
Otherwise, DoEvents is going to call a method that doesn't exist anymore.
Remember that after receiving the WM_DESTROY message, the message pump must still exist to process the PostQuitMessage. If you delete the class, the pWindow pointer of pWindow.DoEvents is no longer valid.
Thanks Jose! I have now made those changes. :)
The gpf is in my version of the color selection combobox. I see mistakes where I forgot to change code when going from ANSI to the UNICODE version. I should have it all fixed by tomorrow.
Updated the first post with the latest code.
Fixed gpfs on 64 bit.
Now using Jose's COM implementation of the FileOpenDialog (AfxIFileOpenDialogW).
Paul,
Looks good but no menu items working except Exit and Environment the latter is still a bit goofy.
Sometimes it gpf's other times not. Setting paths and or the help path can trigger a gpf.
Sometimes the popup just shows the headings.
James
Win10 and fb64
Hmmm... I am wondering if the gpfs are related to using Jose's new COM version of the FileOpenDialog? I hope that I am using it correctly. I need to track down 100% of why the gpfs occur. It seems to happen on 64 bit more often.
I haven't moved the code for the other menu items there yet because I wanted to nail down the core of the environment options first. The techniques I learn there will help me using the CWindow class throughout the rest of the editor. I have huge chunks of code ready to put into the editor because I had already a large portion of the editor using FireFly. Lots of code is based on Jose's code from his SED Editor.
Quote from: James Fuller on June 07, 2016, 05:29:28 PM
Sometimes the popup just shows the headings.
That's interesting. I have never seen that happen in all my tests.
Quote from: TechSupport on June 07, 2016, 06:03:42 PM
Quote from: James Fuller on June 07, 2016, 05:29:28 PM
Sometimes the popup just shows the headings.
That's interesting. I have never seen that happen in all my tests.
Here are the screen shots.
James
Thanks James! Not sure why that would happen. If it happens again then maybe you can run Spy.exe and examine the main options window to see if the 3 child windows exist. Tey should be named FBWindowClass:2, FBWindowClass:3, and FBWindowClass:4. Maybe they are created but now being shown correctly by my code.
My code calls:
TreeView_SelectItem( hWndTreeview, hItem)
and that should trigger the TVN_SELCHANGED notification. The code that responds to that notification hides/shows the correct child window and moves it into place.
I have updated the initial post with new source code. I moved the DELETE pWindow code out of the WM_DESTROY for each of the 3 child sub-forms of the Options Dialog. I moved it a place after the main Options dialog is destroyed. I recompiled and ran the program several times and have not seen a GPF. I have also changed some code that I think was wrong related to using the function SetWindowTextW.
Please let me know if you continue to see any GPFs.
Thanks!
Hi Paul,
One thing that you have to change is pWindow->GetControlWindowRect( hLabel, @rc ) to GetWindowRect( hLabel, @rc ).
' Move the child Form into place. The child form will be displayed under the header label.
Dim rc As Rect
' pWindow->GetControlWindowRect( hLabel, @rc )
GetWindowRect( hLabel, @rc )
MapWindowPoints( Null, HWnd, Cast(LPPOINT, @rc), 2 )
SetWindowPos hForm, HWND_TOP, _
rc.Left + pWindow->ScaleX(5), pWindow->ScaleY(50), _
pWindow->ScaleX(370), pWindow->ScaleY(300), _
SWP_SHOWWINDOW
InvalidateRect HWnd, ByVal Null, True
UpdateWindow HWnd
The CWindow Rect functions, and also others, return unscaled values suitable to be used when they are going to be passed to another CWindow function that will scale them. But as MapWindowPoints s an API function, we have to pass the scaled values (as the windows and controls are already scaled, GetWindowRect will return the correct values).
Another way to do it:
Dim rc As Rect
GetWindowRect( hLabel, @rc )
MapWindowPoints( Null, HWnd, Cast(LPPOINT, @rc), 2 )
' // Unscale rc.Left because SetWindowPos will scale the values
rc.Left /= pWindow->rxRatio
pWindow->SetWindowPos hForm, HWND_TOP, _
rc.Left + 5, 50, _
370, 300, _
SWP_SHOWWINDOW
That is, CWindow methods such CWindow.GetWindowRect, CWindow.GetClientRect, CWindow.GetControlWindowRect, CWindow.ControlWidth or CWindow.ControlHeight, return unscaled values suitable to be passed to another CWindow method.
But if the target is an API function, then use the API counterparts, such GetWindowRect or GetClientRect. Otherwise, you will be passing unscaled values to functions that don't scale them.
Clear as mud :)
After my change, it looks correct in my computer, at 192 DPI. See the capture.
In the CTabPage class of CWindow, the method that creates the tab page unscales the values because the Create method will scale them.
.GetWindowRect(hTab, @rc)
.SendMessageW hTab, TCM_ADJUSTRECT, FALSE, CAST(lParam, @rc)
.MapWindowPoints NULL, hTab, CAST(LPPOINT, @rc), 2
' // Adjust for High DPI because create will resize the values
rc.Left /= this.rxRatio
rc.Right /= this.rxRatio
rc.Top /= this.ryRatio
rc.Bottom /= this.ryRatio
' // Calculate coordinates and size
x = rc.Left
y = rc.Top
nWidth = max(1, rc.Right - rc.Left)
nHeight = max(1, rc.Bottom - rc.Top)
m_hTabPage = this.Create(hTab, wszTitle, lpfnWndProc, x, y, nWidth, nHeight, dwStyle, dwExStyle)
but in the method that resizes the pages I don't unscale anything because I'm just caling API functions.
DIM rcParent AS RECT
.GetWindowRect(hTab, @rcParent)
' // Calculates the tab control's display area given its window rectangle
.SendMessageW(hTab, TCM_ADJUSTRECT, FALSE, CAST(LPARAM, @rcParent))
' // Convert to window coordinates
.MapWindowPoints(NULL, hTab, CAST(LPPOINT, @rcParent), 2)
' // Move the tab page
.MoveWindow(pTabPage->hTabPage, rcParent.Left, rcParent.Top, _
rcParent.Right - rcParent.Left, rcParent.Bottom - rcParent.Top, CTRUE)
Yup, clear as mud :)
I have made the changes and I'll try to remember this as I continue coding the application. :)
Another suggested change:
In modCBColor.inc, change
SelectFont( lpdis->hDC, GetStockObject(DEFAULT_GUI_FONT) )
to
SelectFont( lpdis->hDC, AfxCWindowPtr(hwnd)->Font)
With GetStockObject(DEFAULT_GUI_FONT) the font appears smaller than it should in my system.
With SelectFont( lpdis->hDC, AfxCWindowPtr(hwnd)->Font) it will use the same scaled font that the main window.
Notice the convenience of AfxCWindowPtr(hwnd), a clever function that not only allows you to retrieve the CWindow pointer passing the handle of the main window or the handle of any of its child controls, but also lets you to call the methods of CWindow directly, using the -> notation, without having to do:
DIM pWindow AS CWindow PTR
pWindow = AfxCWindowPtr(hwnd)
pWindow->Font
BTW I'm working in wrappers for the common controls.
AfxCWindowPtr(hwnd)->Font
That syntax is very clever!
Yes, i am making the change right now. :)
Quote from: Jose Roca on June 07, 2016, 11:02:27 PM
BTW I'm working in wrappers for the common controls.
Definitely looking forward to these wrappers!
My next step now is to revisit the class structure that I set up for document handling. I want the editor to be able to handle multiple projects at once.
Workspace
-- Project 1
---- File 1
---- File 2
---- File 3
---- etc
-- Project 2
-- etc
Each project will need to be able to specify compiler options. Likewise, each file within a project needs to be able to have compiler options specified (because some files may be compiled into OBJ and then linked to the main BAS).
Also, need to think about how to handle the build process so that only dirty files are recompiled (unless Rebuild All is specified).
Just starting to think about this stuff but it is important to get it right because the entire guts of the editor will then revolve around it.
Quote from: TechSupport on June 07, 2016, 11:05:28 PM
AfxCWindowPtr(hwnd)->Font
That syntax is very clever!
Yes, i am making the change right now. :)
That's a technique that I suggested to the late Bob Zale to improve the PB COM support and that I called calculated object reference. FB classes are not COM classes, but the principle is the same, only the way to achieve it differs. Fortunetely, some clever guys did a good job implementing function pointers in FB, so it has been easy.
I tried hard to modernize PB programming, but apparently my techniques are above most PBer's heads. DDT has triumphed and it wil turn against them.