Main Menu

Recent posts

#21
PlanetSquires Software / No visible text in the editor ...
Last post by Dennis Hoskins - December 27, 2025, 12:19:27 PM
Hello Paul,

I had started using the 1.26 version of the tiko editor and trying Jose's AfxNova template examples. All was working well until, one morning, no text was visible in the editor pane.

I have closed and restarted tiko. I have switched between light and dark themes. I have copied the tiko.exe and tiko.tiko files from the development branch. I looked for anything that seemed relevant in the preferences. All without fixing the issue.

And then, almost accidently, I double clicked in the editor pane and now the text is visible again. If I double or triple click now, I select text as I would expect.

Any thoughts on what might have happened?

Dennis
#22
José Roca Software / Re: Mdi example question
Last post by José Roca - December 23, 2025, 04:23:06 AM
I don't added support for MDI. It it obsolete and deprecated by Microsoft. Current applications use tabbed interfaces instead of MDI.
#23
José Roca Software / Mdi example question
Last post by Frank Bruebach - December 22, 2025, 02:45:10 PM
hello jose, it's possible to translate this mdi framework demo to afxnova?
thanks, frank

' ########################################################################################
' Microsoft Windows
' File: CW_MDIDemo.pbtpl
' Contents: CWindow MDI Framework Demo
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2016 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
#define USEMDI
#INCLUDE ONCE "Afx/CWindow.inc"
USING Afx

' // Edit control identifier
CONST IDC_EDIT = 101

' // Menu identifiers
ENUM
   IDM_NEW = 1001     ' New file
   IDM_OPEN           ' Open file...
   IDM_SAVE           ' Save file
   IDM_SAVEAS         ' Save file as...
   IDM_EXIT           ' Exit

   IDM_UNDO = 2001    ' Undo
   IDM_CUT            ' Cut
   IDM_COPY           ' Copy
   IDM_PASTE          ' Paste

   IDM_TILEH = 3001   ' Tile hosizontal
   IDM_TILEV          ' Tile vertical
   IDM_CASCADE        ' Cascade
   IDM_ARRANGE        ' Arrange icons
   IDM_CLOSE          ' Close
   IDM_CLOSEALL       ' Close all
END ENUM

DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                          BYVAL hPrevInstance AS HINSTANCE, _
                          BYVAL szCmdLine AS ZSTRING PTR, _
                          BYVAL nCmdShow AS LONG) AS LONG

   END WinMain(GetModuleHandleW(NULL), NULL, COMMAND(), SW_NORMAL)

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

' ========================================================================================
' Build the menu
' ========================================================================================
FUNCTION BuildMenu () AS HMENU

   DIM hMenu AS HMENU
   DIM hPopUpMenu AS HMENU

   hMenu = CreateMenu
   hPopUpMenu = CreatePopUpMenu
      AppendMenuW hMenu, MF_POPUP OR MF_ENABLED, CAST(UINT_PTR, hPopUpMenu), "&File"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_NEW, "&New" & CHR(9) & "Ctrl+N"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_OPEN, "&Open..." & CHR(9) & "Ctrl+O"
         AppendMenuW hPopUpMenu, MF_SEPARATOR, 0, ""
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_SAVE, "&Save" & CHR(9) & "Ctrl+S"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_SAVEAS, "Save &As..."
         AppendMenuW hPopUpMenu, MF_SEPARATOR, 0, ""
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_EXIT, "E&xit" & CHR(9) & "Alt+F4"
   hPopUpMenu = CreatePopUpMenu
      AppendMenuW hMenu, MF_POPUP OR MF_ENABLED, CAST(UINT_PTR, hPopUpMenu), "&Edit"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_UNDO, "&Undo" & CHR(9) & "Ctrl+Z"
         AppendMenuW hPopUpMenu, MF_SEPARATOR, 0, ""
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_CUT, "Cu&t" & CHR(9) & "Ctrl+X"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_COPY, "&Copy" & CHR(9) & "Ctrl+C"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_PASTE, "&Paste" & CHR(9) & "Ctrl+V"
   hPopUpMenu = CreatePopUpMenu
      AppendMenuW hMenu, MF_POPUP OR MF_ENABLED, CAST(UINT_PTR, hPopUpMenu), "&Window"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_TILEH, "&Tile Horizontal"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_TILEV, "Tile &Vertical"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_CASCADE, "Ca&scade"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_ARRANGE, "&Arrange &Icons"
         AppendMenuW hPopUpMenu, MF_SEPARATOR, 0, ""
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_CLOSE, "&Close" & CHR(9) & "Ctrl+F4"
         AppendMenuW hPopUpMenu, MF_ENABLED, IDM_CLOSEALL, "Close &All"
   FUNCTION = hMenu

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

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                  BYVAL hPrevInstance AS HINSTANCE, _
                  BYVAL szCmdLine AS ZSTRING PTR, _
                  BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   AfxSetProcessDPIAware

   ' // Create the main window
   DIM pWindow AS CWindow
   pWindow.Create(NULL, "MDI with CWindow", @WndProc)
   ' // Change the window style to avoid flicker
   pWindow.ClassStyle = CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 650, 400
   ' // Center the window
   pWindow.Center

   ' // Create a menu
   DIM hMenu AS HMENU
   hMenu = BuildMenu
   SetMenu pWindow.hWindow, hMenu

   '// Create a MDI client child window
   DIM hwindowMenu AS HMENU
   hwindowMenu = GetSubMenu(hMenu, 2)
   pWindow.CreateMDIWindow(101, 0, 0, 0, 0, 0, 0, hwindowMenu, @MDIWindowProc)

   ' // Dispatch Windows messages
   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

   STATIC hwndClient AS HWND    ' // Handle of the MDI client window
   DIM hwndActive AS HWND       ' // Active window
   DIM ptnmhdr AS NMHDR PTR     ' // Information about a notification message
   DIM hMdi AS HWND             ' // MDI child window handle
   STATIC nIdx AS LONG          ' // Counter
   STATIC pWindow AS CWindow PTR

   FUNCTION = 0

   ' // Retrieve the MDI client window handle
   IF hwndClient = NULL AND pWindow <> NULL THEN hwndClient = pWindow->hwndClient

   SELECT CASE AS CONST uMsg

      CASE WM_CREATE
         ' // Retrieve a reference to the CWindow class from the CREATESTRUCT structure
         pWindow = AfxCWindowPtr(lParam)
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE GET_WM_COMMAND_ID(wParam, lParam)
            CASE IDCANCEL
               IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

            ' // New window
            CASE IDM_NEW
               IF hwndClient THEN
                  nIdx += 1
                  DIM mdi AS MDICREATESTRUCTW, dwStyle AS DWORD
                  IF IsZoomed(CAST(HWND, SendMessageW(hwndClient, WM_MDIGETACTIVE, 0, 0))) THEN dwStyle = WS_MAXIMIZE
                  hMdi = CreateWindowExW(WS_EX_MDICHILD OR WS_EX_CLIENTEDGE, "FBFrameClass", "", _
                           dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, _
                           hwndClient, NULL, CAST(HANDLE, GetWindowLongPtrW(hwndClient, GWLP_HINSTANCE)), NULL)
                  SetWindowTextW hMdi, "MDI Child Window " & WSTR(nIdx)
               END IF
               EXIT FUNCTION

            ' // Tile horizontally
            CASE IDM_TILEH
               IF hwndClient THEN SendMessageW hwndClient, WM_MDITILE, MDITILE_HORIZONTAL, 0
               EXIT FUNCTION

            ' // Tile vertically
            CASE IDM_TILEV
               IF hwndClient THEN SendMessageW hwndClient, WM_MDITILE, MDITILE_VERTICAL, 0
               EXIT FUNCTION

            ' // Cascade windows
            CASE IDM_CASCADE
               IF hwndClient THEN SendMessageW hwndClient, WM_MDICASCADE, 0, 0
               EXIT FUNCTION

            ' // Arrange icons
            CASE IDM_ARRANGE
               IF hwndClient THEN SendMessageW hwndClient, WM_MDIICONARRANGE, 0, 0
               EXIT FUNCTION

            CASE IDM_CLOSE
               ' // Close the active window
               IF hwndClient THEN
                  hwndActive = CAST(HANDLE, SendMessageW(hwndClient, WM_MDIGETACTIVE, 0, 0))
                  IF SendMessageW(hwndActive, WM_QUERYENDSESSION, 0, 0) THEN
                     SendMessageW hwndClient, WM_MDIDESTROY, CAST(LPARAM, hwndActive), 0
                  END IF
               END IF
               EXIT FUNCTION

            CASE IDM_CLOSEALL
               ' // Close all the MDI child windows
               IF hwndClient THEN
                  EnumChildWindows hwndClient, @CWindow_CloseEnumProc, 0
               END IF
               EXIT FUNCTION

            ' // Exit the application
            CASE IDM_EXIT
               SendMessageW hwnd, WM_CLOSE, 0, 0
               EXIT FUNCTION

         END SELECT

         ' // Pass unprocessed messages to the active MDI child and then to DefFrameProc()
         hwndActive = CAST(HWND, SendMessageW(hwndClient, WM_MDIGETACTIVE, 0, 0))
         IF IsWindow(hwndActive) THEN SendMessageW hwndActive, WM_COMMAND, wParam, lParam

      CASE WM_NOTIFY
         ptnmhdr = CAST(NMHDR PTR, lParam)
'         SELECT CASE ptnmhdr->idFrom
'            ' ...
'            ' ...
'         END SELECT

         ' // Pass unprocessed messages to the active MDI child and then to DefFrameProc()
         IF hwndClient THEN
            hwndActive = CAST(HWND, SendMessageW(hwndClient, WM_MDIGETACTIVE, 0, 0))
            IF IsWindow(hwndActive) THEN SendMessageW hwndActive, WM_NOTIFY, wParam, lParam
         END IF

      CASE WM_SIZE
         ' // If the window isn't minimized, resize it
         IF wParam <> SIZE_MINIMIZED THEN
            IF hwndClient <> NULL AND pWindow <> NULL THEN
               pWindow->MoveWindow hwndClient, 0, 0, pWindow->ClientWidth + 2, pWindow->ClientHeight + 2, CTRUE
            END IF
         END IF
         ' // Note: This message is not passed to DefFrameProc when space
         ' // is being reserved in the client area of the MDI frame
         ' // or controls on the MDI frame are resizeable.
         EXIT FUNCTION

      CASE WM_CLOSE
         IF hwndClient THEN
            ' // Attempt to close all MDI child windows
            EnumChildWindows hwndClient, @CWindow_CloseEnumProc, 0
            ' // If child windows are still open abort closing the application
            IF GetWindow(hwndClient, GW_CHILD) THEN EXIT FUNCTION
         END IF

      CASE WM_QUERYENDSESSION
         IF hwndClient THEN
            ' // Attempt to close all MDI child windows
            EnumChildWindows hwndClient, @CWindow_CloseEnumProc, 0
            ' // If child windows are still open abort closing the application
            IF GetWindow(hwndClient, GW_CHILD) THEN EXIT FUNCTION
         END IF

    CASE WM_DESTROY
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   IF hwndClient THEN
   ' // The DefFrameProc function provides default processing for any window
   ' // messages that the window procedure of a multiple-document interface (MDI)
   ' // frame window does not process. All window messages that are not explicitly
   ' // processed by the window procedure must be passed to the DefFrameProc
   ' // function, not the DefWindowProc function.
      FUNCTION = DefFrameProcW(hwnd, hwndClient, uMsg, wParam, lParam)
   ELSE
   ' // The DefWindowProc function 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. DefWindowProc
   ' // is called with the same parameters received by the window procedure.
      FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)
   END IF

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

' ========================================================================================
' Default CWindow MDI callback function.
' ========================================================================================
FUNCTION MDIWindowProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM hEdit AS HWND
   DIM rc AS RECT

   SELECT CASE uMsg

      CASE WM_CREATE
         ' // Retrieve a pointer to the CWindow class
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(GetAncestor(hwnd, GA_ROOTOWNER))
         ' // Create and edit control
         IF pWindow THEN
            GetClientRect hwnd, @rc
            pWindow->AddControl("Edit", hwnd, IDC_EDIT, "", 0, 0, rc.Right, rc.Bottom, _
               WS_CHILD OR WS_VISIBLE OR ES_MULTILINE OR WS_VSCROLL OR WS_HSCROLL OR ES_AUTOHSCROLL OR ES_AUTOVSCROLL OR ES_WANTRETURN OR ES_NOHIDESEL)
            EXIT FUNCTION
         END IF

      CASE WM_MDIACTIVATE
         IF lParam = hwnd THEN
            ' ...
         END IF
         EXIT FUNCTION

      CASE WM_SETFOCUS
         ' // Set the keyboard focus to the first control that is
         ' // visible, not disabled, and has the WS_TABSTOP style
         SetFocus GetNextDlgTabItem(hwnd, NULL, FALSE)

      CASE WM_SIZE
         IF wParam <> SIZE_MINIMIZED THEN
            ' // Resize the window and/or its controls
            hEdit = GetDlgItem(hwnd, IDC_EDIT)
            MoveWindow hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), CTRUE
         END IF

         ' Don't exit. Let DefMDIChildProcW to process the message for
         ' properly resizing of the MDI child window.

      CASE WM_DESTROY
         ' // Do cleanup if needed, such removing properties attached
         ' // to the MDI child window.
         EXIT FUNCTION

   END SELECT

   ' // The DefMDIChildProc function provides default processing for any window
   ' // message that the window procedure of a multiple-document interface (MDI)
   ' // child window does not process. A window message not processed by the window
   ' // procedure must be passed to the DefMDIChildProc function, not to the
   ' // DefWindowProc function.
   FUNCTION = DefMDIChildProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================
#25
General Board / Re: imagination and GUI design
Last post by Johan Klassen - December 17, 2025, 08:57:01 AM
thanks Paul and José  :)
#26
José Roca Software / Re: AfxNova progress
Last post by José Roca - December 16, 2025, 07:58:06 PM
I'm wrapping now XmlLite, to have a fast parser and writer for the XML format. I'm now in the phase of the documentation.
#27
José Roca Software / Re: AfxNova progress
Last post by José Roca - December 16, 2025, 07:54:56 PM
I have removed the duplicated lines. Thanks again.
#28
José Roca Software / Re: AfxNova progress
Last post by José Roca - December 16, 2025, 07:46:14 PM
Thanks very much. I will check it. It is a problem of copy and paste. You copy a line to keep the fomatting and change the text, and sometimes you get distracted and forget to change it. Documentation is the worst part. Nobody likes to do it, but I make the effort of documenting all my code. A documentation like the one for GDI+, with 600+ functions, is very hard to do without doing some mistakes.
#29
General Board / Re: imagination and GUI design
Last post by José Roca - December 16, 2025, 05:17:44 PM
I only used a visual designer once, just for trying. I prefer to code by hand: it takes more time to design the gui, but I have absolute control. I have writen small templates for each control. They allow me to remember its particularities. They are like notes, but with working code. CWindow is a class on top of CreateWindowEx that simplifies several boring tasks of SDK programming, like registering classes, providing default styles for the controls, resizing, colors and scaling according the DPI. It also provides a default message pump that is useful in most cases, but it is optional: you can use your own message pump. Most of the features of CWindow are optional. You can use AddControl or you can use CreateWindowEx; you can anchor the controls for automatic resizing or you don't and do it in WM_SIZE; you can set colors for static controls, or you don't and process the CTL_XXX messages, etc. That is, you aren't forced to use all its features, only these that you wish. For the rest, you can use your own progeamming style instead of being forced to follow the rules of the visual designer (this is the part that I don't like of them).
#30
General Board / Re: imagination and GUI design
Last post by Paul Squires - December 16, 2025, 11:02:18 AM
Interesting question.

A lot of times when I'm creating a new program, I research existing applications with similar functionality. I create a folder of screenshots containing main screens, data entry screens, etc. I save pictures of traditional desktop applications and newer web based applications. I also take note of colors and themes, not just control layouts.

The physical act of coding the GUI in code is not that difficult. It just involves ensuring that spacing and sizing of the controls is correct and that entails a lot of trial and error and compile after compile to chekc your progress. However, once you've created a button, listbox, etc, then a quick copy/paste and changing the positioning parameters is easy.

Usually resizing a window and repositioning all of the controls within that window is a tedious task when done from WM_SIZE, but José has already taken care of that within the AfxNova library via his positioning rules.

I think, like everything, the more you code GUI's via code, the easier it becomes. In my programming lifetime, I have used both visual designers and hand coding. Each has it's pluses and minuses. Coding by hand certainly ensures and reinforces that you understand the underlying code whereas sometimes with visual designers you become too reliant on the black box magic that the visual designer is pumping out for you. I will say though that the older I get, the more I use hand coding. It tends to future proof your code because the code is no longer tied to a specific visual designer.