How to draw on dialog with DDT

Started by docroger, July 22, 2025, 07:05:46 AM

Previous topic - Next topic

docroger

Hello José,

Can you give me a small example how to draw (line, point, box, etc) on a dialog.
I use DDT with afxnova.

On powerbasic there is graphic attach, graphic line... etc...

Thanx for any help.

José Roca

I'm not going to replicate the GRAPHIC statements. Instead, I'm working in my own Graphic control that works with GDI, GDI+ and OpenGL. It is a SDK custom control. I will see if I can make it to work with dialogs.

To draw in  a dialog using GDI, you have to do it processing the WM_PAINT message ad, if the dialog is resizable, also the WM_ERASEBKGND message.

Here is an small example:

#define UNICODE
#define _WIN32_WINNT &h0602
#include once "AfxNova/DDT.inc"
USING AfxNova

DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                           BYVAL hPrevInstance AS HINSTANCE, _
                           BYVAL pwszCmdLine AS WSTRING PTR, _
                           BYVAL nCmdShow AS LONG) AS LONG
   END wWinMain(GetModuleHandleW(NULL), NULL, wCommand(), SW_NORMAL)

DECLARE FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR

CONST IDC_OK = 1001

' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                   BYVAL hPrevInstance AS HINSTANCE, _
                   BYVAL pwszCmdLine AS WSTRING PTR, _
                   BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)

   ' // Create a new dialog using dialog units
   DIM hDlg AS HWND = DialogNewPixels(0, "DDT Dialog - GDI Line Demo", 0, 0, 400, 220, WS_POPUP OR WS_CAPTION OR WS_SYSMENU OR DS_CENTER)
   ' // Set the dialog's backgroung color
   DialogSetColor(hDlg, -1, RGB_WHITE)

   ' // Display and activate the dialog as modal
   DialogShowModal(hDlg, @DlgProc)

   RETURN DialogEndResult(hDlg)

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

' ========================================================================================
' Dialog callback procedure
' ========================================================================================
FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR

   STATIC cxClient AS LONG, cyClient AS LONG
   
   SELECT CASE uMsg

      CASE WM_INITDIALOG
         RETURN TRUE

      CASE WM_COMMAND
         SELECT CASE CBCTL(wParam, lParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application by sending an WM_CLOSE message
               IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
                  SendMessageW hDlg, WM_CLOSE, 0, 0
               END IF
            CASE IDC_OK
               MsgBox("OK button pressed", MB_ICONEXCLAMATION OR MB_TASKMODAL, "Message")
         END SELECT

      CASE WM_PAINT
         DIM ps AS PAINTSTRUCT
         DIM hdc AS HDC = BeginPaint(hDlg, @ps)
         Rectangle hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8
         MoveToEx hdc, 0, 0, NULL
         LineTo hdc, cxClient, cyClient
         MoveToEx hdc, 0, cyClient, NULL
         LineTo hdc, cxClient, 0
         Ellipse hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8
         RoundRect hdc, cxClient / 4, cyClient / 4, 3 * cxClient / 4, 3 * cyClient / 4, cxClient / 4, cyClient / 4
         EndPaint hDlg, @ps
         RETURN TRUE

      CASE WM_SIZE
         cxClient = LOWORD(lParam)
         cyClient = HIWORD(lParam)
         RETURN TRUE

      CASE WM_CLOSE
         ' // End the application
         DialogEnd(hDlg)

   END SELECT

   RETURN FALSE

END FUNCTION

For documentation about GDI see: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-rectangle

José Roca

#2
My GdiPlus classes (working on it) can also be used. You can't compile it because I'm still working in the GdiPlus classes.

#define UNICODE
#define _WIN32_WINNT &h0602
#include once "AfxNova/DDT.inc"
#include once "AfxNova/CGdiPlus.inc"
USING AfxNova

DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                           BYVAL hPrevInstance AS HINSTANCE, _
                           BYVAL pwszCmdLine AS WSTRING PTR, _
                           BYVAL nCmdShow AS LONG) AS LONG
   END wWinMain(GetModuleHandleW(NULL), NULL, wCommand(), SW_NORMAL)

DECLARE FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR

CONST IDC_OK = 1001

' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                   BYVAL hPrevInstance AS HINSTANCE, _
                   BYVAL pwszCmdLine AS WSTRING PTR, _
                   BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)

   ' // Create a new dialog using dialog units
   DIM hDlg AS HWND = DialogNewPixels(0, "DDT Dialog - GDI Line Demo", 0, 0, 400, 220, WS_POPUP OR WS_CAPTION OR WS_SYSMENU OR DS_CENTER)
   ' // Set the dialog's backgroung color
   DialogSetColor(hDlg, -1, RGB_WHITE)

   ' // Display and activate the dialog as modal
   DialogShowModal(hDlg, @DlgProc)

   RETURN DialogEndResult(hDlg)

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

' ========================================================================================
' The following example creates an AdjustableArrowCap, myArrow, and sets the height of the
' cap. The code then creates a Pen, assigns myArrow as the ending line cap for the Pen,
' and draws a capped line. Next, the code gets the height of the arrow cap, creates a new
' arrow cap with height equal to the height of myArrow, assigns the new arrow cap as the
' ending line cap for the Pen, and draws another capped line.
' ========================================================================================
SUB Example_GetHeight (BYVAL hdc AS HDC)

   ' // Create a graphics object from the window device context
   DIM graphics AS CGpGraphics = hdc
   ' // Get the DPI scaling ratios
   DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
   DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
   ' // Set the scale transform
   graphics.ScaleTransform(rxRatio, ryRatio)

   ' // Create an AdjustableArrowCap with a height of 10 pixels
   DIM myArrow AS CGpAdjustableArrowCap = CGpAdjustableArrowCap(10, 10, TRUE)
   ' // Adjust to DPI by setting the scale width
   myArrow.SetWidthScale(rxRatio)

   ' // Create a Pen, and assign myArrow as the end cap
   DIM arrowPen AS CGpPen = ARGB_Violet
   arrowPen.SetCustomEndCap(@myArrow)

   ' // Draw a line using arrowPen
   graphics.DrawLine(@arrowPen, 0, 20, 100, 20)

   ' // Create a second arrow cap using the height of the first one
   DIM AS CGpAdjustableArrowCap otherArrow = CGpAdjustableArrowCap(myArrow.GetHeight, 20, TRUE)
   otherArrow.SetWidthScale(rxRatio)

   ' // Assign the new arrow cap as the end cap for arrowPen
   arrowPen.SetCustomEndCap(@otherArrow)

   ' // Draw a line using arrowPen
   graphics.DrawLine(@arrowPen, 0, 55, 100, 55)

END SUB
' ========================================================================================

' ========================================================================================
' Dialog callback procedure
' ========================================================================================
FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR

   SELECT CASE uMsg

      CASE WM_INITDIALOG
         RETURN TRUE

      CASE WM_COMMAND
         SELECT CASE CBCTL(wParam, lParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application by sending an WM_CLOSE message
               IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
                  SendMessageW hDlg, WM_CLOSE, 0, 0
               END IF
            CASE IDC_OK
               MsgBox("OK button pressed", MB_ICONEXCLAMATION OR MB_TASKMODAL, "Message")
         END SELECT

      CASE WM_PAINT
         DIM ps AS PAINTSTRUCT
         DIM hdc AS HDC = BeginPaint(hDlg, @ps)
         Example_GetHeight(hdc)
         EndPaint hDlg, @ps
         RETURN TRUE

      CASE WM_CLOSE
         ' // End the application
         DialogEnd(hDlg)

   END SELECT

   RETURN FALSE

END FUNCTION

José Roca

My graphic control features persistence, so you don't have to be constantly repainting it. This is a SDK test. You can't compile it because I'm still working in the GdiPlus classes.

' ########################################################################################
' Microsoft Windows
' File: AdjustableArrowCapGetHeight.bas
' Contents: GDI+ - AdjustableArrowCapGetHeight example
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2025 José Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#define UNICODE
#INCLUDE ONCE "AfxNova/CGdiPlus.inc"
#INCLUDE ONCE "AfxNova/CGraphCtx.inc"
USING AfxNova

CONST IDC_GRCTX = 1001

DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                           BYVAL hPrevInstance AS HINSTANCE, _
                           BYVAL pwszCmdLine AS WSTRING PTR, _
                           BYVAL nCmdShow AS LONG) AS LONG

   END wWinMain(GetModuleHandleW(NULL), NULL, wCOMMAND(), SW_NORMAL)

' // Forward declaration
DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

' ========================================================================================
' The following example creates an AdjustableArrowCap, myArrow, and sets the height of the
' cap. The code then creates a Pen, assigns myArrow as the ending line cap for the Pen,
' and draws a capped line. Next, the code gets the height of the arrow cap, creates a new
' arrow cap with height equal to the height of myArrow, assigns the new arrow cap as the
' ending line cap for the Pen, and draws another capped line.
' ========================================================================================
SUB Example_GetHeight (BYVAL hdc AS HDC)

   ' // Create a graphics object from the window device context
   DIM graphics AS CGpGraphics = hdc
   ' // Get the DPI scaling ratios
   DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
   DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
   ' // Set the scale transform
   graphics.ScaleTransform(rxRatio, ryRatio)

   ' // Create an AdjustableArrowCap with a height of 10 pixels
   DIM myArrow AS CGpAdjustableArrowCap = CGpAdjustableArrowCap(10, 10, TRUE)
   ' // Adjust to DPI by setting the scale width
   myArrow.SetWidthScale(rxRatio)

   ' // Create a Pen, and assign myArrow as the end cap
   DIM arrowPen AS CGpPen = ARGB_Violet
   arrowPen.SetCustomEndCap(@myArrow)

   ' // Draw a line using arrowPen
   graphics.DrawLine(@arrowPen, 0, 20, 100, 20)

   ' // Create a second arrow cap using the height of the first one
   DIM AS CGpAdjustableArrowCap otherArrow = CGpAdjustableArrowCap(myArrow.GetHeight, 20, TRUE)
   otherArrow.SetWidthScale(rxRatio)

   ' // Assign the new arrow cap as the end cap for arrowPen
   arrowPen.SetCustomEndCap(@otherArrow)

   ' // Draw a line using arrowPen
   graphics.DrawLine(@arrowPen, 0, 55, 100, 55)

END SUB
' ========================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                   BYVAL hPrevInstance AS HINSTANCE, _
                   BYVAL pwszCmdLine AS WSTRING PTR, _
                   BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
   ' // Enable visual styles without including a manifest file
   AfxEnableVisualStyles

   ' // Create the main window
   DIM pWindow AS CWindow = "MyClassName"
   pWindow.CreateOverlapped(NULL, "GDI+ AdjustableArrowCapGetHeight", @WndProc)
   ' // Size it by setting the wanted width and height of its client area
   pWindow.SetClientSize(400, 250)
   ' // Center the window
   pWindow.Center

   ' // Add a graphic control
   DIM pGraphCtx AS CGraphCtx = CGraphCtx(@pWindow, IDC_GRCTX, "", 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
   pGraphCtx.Clear RGB_FLORALWHITE
   ' // Get the memory device context of the graphic control
   DIM hdc AS HDC = pGraphCtx.GetMemDc
   ' // Draw the graphics
   Example_GetHeight(hdc)

   ' // Displays the window and dispatches the Windows messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

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

' ========================================================================================
' Main window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   SELECT CASE uMsg

      ' // If an application processes this message, it should return zero to continue
      ' // creation of the window. If the application returns –1, the window is destroyed
      ' // and the CreateWindowExW function returns a NULL handle.
      CASE WM_CREATE
         AfxEnableDarkModeForWindow(hwnd)
         EXIT FUNCTION

      ' // Theme has changed
      CASE WM_THEMECHANGED
         AfxEnableDarkModeForWindow(hwnd)
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE CBCTL(wParam, lParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application by sending an WM_CLOSE message
               IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

    CASE WM_DESTROY
         ' // Ends the application by sending a WM_QUIT message
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Default processing of Windows messages
   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

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

docroger

Hi José,

Thanx for the explanations.

I test and learn for porting my powerbasic apps.

Is the new graphic control soon available ?

José Roca

#5
Yes. I just have finished the integration. Using my GDI+ classes, that replicate the Microsoft ones, and setting the DPI ratios with ScaleTransform, the graphics are DPI aware and scale automatically. Contrarily to the PowerBasic graphic control, that is a subclassed static control that only works with 24-bit images, CGraphCtx is 32 bit, allowing the use of alpha blended images with transparency and, as it uses DIBs, it has not the 4 MB limitation.

Test example (the attachment contains a 64-bit executable):

' ########################################################################################
' Microsoft Windows
' File: DDT_AdjustableArrowCapGetHeight.bas
' Contents: GDI+ - AdjustableArrowCapGetHeight example
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2025 José Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#define UNICODE
#INCLUDE ONCE "AfxNova/CGdiPlus.inc"
#INCLUDE ONCE "AfxNova/CGraphCtx.inc"
#INCLUDE ONCE "AfxNova/DDT.inc"
#INCLUDE ONCE "AfxNova/AfxExt.bi"   ' // optional: For dark mode
USING AfxNova

CONST IDC_GRCTX = 1001

DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                           BYVAL hPrevInstance AS HINSTANCE, _
                           BYVAL pwszCmdLine AS WSTRING PTR, _
                           BYVAL nCmdShow AS LONG) AS LONG

   END wWinMain(GetModuleHandleW(NULL), NULL, wCOMMAND(), SW_NORMAL)

' // Forward declaration
DECLARE FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR

' ========================================================================================
' The following example creates an AdjustableArrowCap, myArrow, and sets the height of the
' cap. The code then creates a Pen, assigns myArrow as the ending line cap for the Pen,
' and draws a capped line. Next, the code gets the height of the arrow cap, creates a new
' arrow cap with height equal to the height of myArrow, assigns the new arrow cap as the
' ending line cap for the Pen, and draws another capped line.
' ========================================================================================
SUB Example_GetHeight (BYVAL hdc AS HDC)

   ' // Create a graphics object from the window device context
   DIM graphics AS CGpGraphics = hdc
   ' // Get the DPI scaling ratios
   DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
   DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
   ' // Set the scale transform
   graphics.ScaleTransform(rxRatio, ryRatio)

   ' // Create an AdjustableArrowCap with a height of 10 pixels
   DIM myArrow AS CGpAdjustableArrowCap = CGpAdjustableArrowCap(10, 10, TRUE)
   ' // Adjust to DPI by setting the scale width
   myArrow.SetWidthScale(rxRatio)

   ' // Create a Pen, and assign myArrow as the end cap
   DIM arrowPen AS CGpPen = ARGB_Violet
   arrowPen.SetCustomEndCap(@myArrow)

   ' // Draw a line using arrowPen
   graphics.DrawLine(@arrowPen, 0, 20, 100, 20)

   ' // Create a second arrow cap using the height of the first one
   DIM AS CGpAdjustableArrowCap otherArrow = CGpAdjustableArrowCap(myArrow.GetHeight, 20, TRUE)
   otherArrow.SetWidthScale(rxRatio)

   ' // Assign the new arrow cap as the end cap for arrowPen
   arrowPen.SetCustomEndCap(@otherArrow)

   ' // Draw a line using arrowPen
   graphics.DrawLine(@arrowPen, 0, 55, 100, 55)

END SUB
' ========================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                   BYVAL hPrevInstance AS HINSTANCE, _
                   BYVAL pwszCmdLine AS WSTRING PTR, _
                   BYVAL nCmdShow AS LONG) AS LONG

   ' // The recommended way is to use a manifest.
   ' // Optional: Set process DPI aware.
   SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
   ' // Optional: Enable visual styles without including a manifest file
   AfxEnableVisualStyles

   ' // Create a new custom dialog using pixels
'   DIM hDlg AS HWND = DialogNewPixels("MyClassName", 0, "DDT - GraphCtx Test", 0, 0, 400, 250, WS_OVERLAPPEDWINDOW OR DS_CENTER)
   ' // Alternate way: Provides an exact control of the client size
   DIM hDlg AS HWND = DialogNewPixels("MyClassName", 0, "DDT - GraphCtx Test", 0, 0, 0, 0, WS_OVERLAPPEDWINDOW)
   DialogSetClient(hDlg, 400, 250)
   DialogCenter(hDlg)
   ' // Optional: Caption dark mode
   AfxEnableDarkModeForWindow(hDlg)

   ' // Add a graphic control
   DIM nWidth AS LONG = DialogGetClientWidth(hDlg)
   DIM nHeight AS LONG = DialogGetClientHeight(hDlg)
   DIM pGraphCtx AS CGraphCtx = CGraphCtx(hDlg, IDC_GRCTX, "", 0, 0, nWidth, nHeight)
   ' // Make the control resizable
   pGraphCtx.Resizable = TRUE
   ' // Optional: Clear the graphic control background
   pGraphCtx.Clear RGB_FLORALWHITE
   ' // Get the memory device context of the graphic control
   DIM hdc AS HDC = pGraphCtx.GetMemDc

   ' // Pointer version:
'   DIM pGraphCtx AS CGraphCtx = NEW CGraphCtx(hDlg, IDC_GRCTX, "", 0, 0, nWidth, nHeight)
'   --or--
'   DIM pGraphCtx AS CGraphCtx PTR = ControlAddGraphic(hDlg, IDC_GRCTX, "", 0, 0, nWidth, nHeight)
'   pGraphCtx->Resizable = TRUE
'   pGraphCtx->Clear RGB_FLORALWHITE
'   DIM hdc AS HDC = pGraphCtx->GetMemDc

   ' // Draw the graphics
   Example_GetHeight(hdc)

   ' // Display and activate the dialog as modal
   DialogShowModal(hDlg, @DlgProc)

   ' // Pointer version: Delete the graphic control
 '  IF pGraphCtx THEN Delete pGraphCtx

   ' // Return the result code set with DialogEnd
   RETURN DialogEndResult(hDlg)

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

' ========================================================================================
' Dialog callback procedure
' ========================================================================================
FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR

   SELECT CASE uMsg

      CASE WM_INITDIALOG
         RETURN TRUE

      ' // Optional: Theme has changed
'      CASE WM_THEMECHANGED
'         AfxEnableDarkModeForWindow(hDlg)

      CASE WM_COMMAND
         SELECT CASE CBCTL(wParam, lParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application by sending an WM_CLOSE message
               IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
                  SendMessageW hDlg, WM_CLOSE, 0, 0
               END IF
         END SELECT

      CASE WM_CLOSE
         ' // End the application
         DialogEnd(hDlg)

   END SELECT

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

José Roca

It also allows to mix the use of GDI, GDI+ and OpenGL.

' ########################################################################################
' Microsoft Windows
' Contents: CWindow OpenGL Graphic Control Skeleton
' Graphic control, GDI+ classes and OpenGL working together
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2025 José Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#define UNICODE
#INCLUDE ONCE "AfxNova/CWindow.inc"
#INCLUDE ONCE "AfxNova/CGdiPlus.inc"
#INCLUDE ONCE "AfxNova/CGraphCtx.inc"
USING AfxNova

CONST IDC_GRCTX = 1001

DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                           BYVAL hPrevInstance AS HINSTANCE, _
                           BYVAL pwszCmdLine AS WSTRING PTR, _
                           BYVAL nCmdShow AS LONG) AS LONG

   END wWinMain(GetModuleHandleW(NULL), NULL, wCOMMAND(), SW_NORMAL)

' // Forward declaration
DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

' ========================================================================================
' The following sample code draws a line.
' Change it with your own code.
' ========================================================================================
SUB GDIP_Render (BYVAL hDC AS HDC)

   ' // Create a graphics object from the window device context
   DIM graphics AS CGpGraphics = hdc
   ' // Get the DPI scaling ratios
   DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
   DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
   ' // Set the scale transform
   graphics.ScaleTransform(rxRatio, ryRatio)

   ' // Create a Pen object
   DIM pen AS CGpPen = CGpPen(ARGB_GREEN, 15)

   ' // Draw a line
   graphics.DrawLine(@pen, 0, 0, 200, 100)

END SUB
' ========================================================================================

' =======================================================================================
' All the setup goes here
' =======================================================================================
SUB RenderScene (BYVAL nWidth AS LONG, BYVAL nHeight AS LONG)

   ' // Specify clear values for the color buffers
   glClearColor 0.0, 0.0, 0.0, 0.0
   ' // Specify the clear value for the depth buffer
   glClearDepth 1.0
   ' // Specify the value used for depth-buffer comparisons
   glDepthFunc GL_LESS
   ' // Enable depth comparisons and update the depth buffer
   glEnable GL_DEPTH_TEST
   ' // Select smooth shading
   glShadeModel GL_SMOOTH

   ' // Prevent divide by zero making height equal one
   IF nHeight = 0 THEN nHeight = 1
   ' // Reset the current viewport
   glViewport 0, 0, nWidth, nHeight
   ' // Select the projection matrix
   glMatrixMode GL_PROJECTION
   ' // Reset the projection matrix
   glLoadIdentity
   ' // Calculate the aspect ratio of the window
   gluPerspective 45.0!, nWidth / nHeight, 0.1!, 100.0!
   ' // Select the model view matrix
   glMatrixMode GL_MODELVIEW
   ' // Reset the model view matrix
   glLoadIdentity

   ' // Clear the screen buffer
   glClear GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT
   ' // Reset the view
   glLoadIdentity

   glTranslatef -1.5!, 0.0!, -6.0!       ' Move left 1.5 units and into the screen 6.0

   glBegin GL_TRIANGLES                 ' Drawing using triangles
      glColor3f   1.0!, 0.0!, 0.0!       ' Set the color to red
      glVertex3f  0.0!, 1.0!, 0.0!       ' Top
      glColor3f   0.0!, 1.0!, 0.0!       ' Set the color to green
      glVertex3f  1.0!,-1.0!, 0.0!       ' Bottom right
      glColor3f   0.0!, 0.0!, 1.0!       ' Set the color to blue
      glVertex3f -1.0!,-1.0!, 0.0!       ' Bottom left
   glEnd                                 ' Finished drawing the triangle

   glTranslatef 3.0!,0.0!,0.0!           ' Move right 3 units

   glColor3f 0.5!, 0.5!, 1.0!            ' Set the color to blue one time only
   glBegin GL_QUADS                      ' Draw a quad
      glVertex3f -1.0!, 1.0!, 0.0!       ' Top left
      glVertex3f  1.0!, 1.0!, 0.0!       ' Top right
      glVertex3f  1.0!,-1.0!, 0.0!       ' Bottom right
      glVertex3f -1.0!,-1.0!, 0.0!       ' Bottom left
   glEnd                                 ' Done drawing the quad

   ' // Required: force execution of GL commands in finite time
   glFlush

END SUB
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                   BYVAL hPrevInstance AS HINSTANCE, _
                   BYVAL pwszCmdLine AS WSTRING PTR, _
                   BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
   ' // Enable visual styles without including a manifest file
   AfxEnableVisualStyles

   ' // Create the main window
   DIM pWindow AS CWindow
   pWindow.Create(NULL, "CWindow+CGraphCtx+CGdiPlus+OpenGL", @WndProc)
   pWindow.SetClientSize(400, 250)
   pWindow.Center

   ' // Add a graphic control with OPENGL enabled
   DIM pGraphCtx AS CGraphCtx = CGraphCtx(@pWindow, IDC_GRCTX, "OPENGL", 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
   ' // Anchor the control
   pWindow.AnchorControl(IDC_GRCTX, AFX_ANCHOR_HEIGHT_WIDTH)

   ' // Clear the background
   pGraphCtx.Clear RGB_WHITE
   ' // Make the control resizable
   pGraphCtx.Stretchable = TRUE
   ' // Make current the rendering context
   pGraphCtx.MakeCurrent
   ' // Render the OpenGL scene
   RenderScene pGraphCtx.GetVirtualBufferWidth, pGraphCtx.GetVirtualBufferHeight
   ' // Draw the GDI+ graphics
   GDIP_Render pGraphCtx.GetMemDC

   ' // Dispatch Windows events
   FUNCTION = pWindow.DoEvents(nCmdShow)

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

' ========================================================================================
' Main window callback procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   SELECT CASE uMsg

      CASE WM_COMMAND
         SELECT CASE CBCTL(wParam, lParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application by sending an WM_CLOSE message
               IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

    CASE WM_DESTROY
         ' // End the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Default processing of Windows messages
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

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

docroger

Hi, nice examples !!

After try the exe, i try to compile code... but my version afxnova is incomplete... i wait.

Good job.

hajubu

@jose
I know your are in mid of your work - but there some findings for the graphics control
Nvertheless - thank for the great work --
' Graphic control, GDI+ classes and OpenGL working together
' DEMO FILE : GdiPlusAndOpenGL.bas
! wrong folder reference in line 1188...1198 of AfxNova\CGdiPlu.inc
! causes error 23: File not found in '#include once "AfxNova/CGdiPlus/.....inc"'
! starting with
#include once "AfxNova/CGdiPlus/CGpBitmap.inc"
#include once "AfxNova/CGdiPlus/CGpBrush.inc"
#include once "AfxNova/CGdiPlus/CGpFont.inc"
#include once "AfxNova/CGdiPlus/CGpGraphics.inc"
#include once "AfxNova/CGdiPlus/CGpImageAttributes.inc"
#include once "AfxNova/CGdiPlus/CGpLineCaps.inc"
#include once "AfxNova/CGdiPlus/CGpMatrix.inc"
#include once "AfxNova/CGdiPlus/CGpPath.inc"
#include once "AfxNova/CGdiPlus/CGpPen.inc"
#include once "AfxNova/CGdiPlus/CGpRegion.inc"
#include once "AfxNova/CGdiPlus/CGpStringFormat.inc"

! BUT using a correct reference will follow-up with "  declaration outside namespace...."
!      FOR "CGpBitmap.inc ... CGpGraphics.inc"
!  trying to correct this
!  will cause an follow-up segmentation error

José Roca

Thanks very much for reporting it.

Modified "CGdiPlus.inc" and "CGpGraphics.inc"

and uploaded them to the AfxNova repository in GitHub.

José Roca

#10
For GDI+ I'm using my own declarations file, "AfxGdiplus.bi", because the ones provided with the FreeBasic compiler for 32-bit are a truly mess and incompatible with the ones for 64-bit, so I have unified them. The import 32-bit library for GDI+ is also partially broken. Paul Squires has generated a new one that works correctly and that will be included with the new Tiko release. Meanwhile, it is advisable to compile with the 64-bit compiler.