' // Scroll bars dark theme
SetWindowTheme(pGrid.hwnd, "DarkMode_Explorer", NULL)
' // Change the foreground and background colors
pGrid.ForeColor = RGB_WHITE
pGrid.BackColor = RGB_BLACK
' // change the color of the background of the grid
pGrid.BackColorBkg = RGB_BLACK
' // Change the colors of the fixed parts of the grid
pGrid.ForeColorFixed = RGB_WHITE
pGrid.BackColorFixed = BGR(90, 90, 90)
' // Color of the grid
pGrid.GridColor = RGB_GRAY
pGrid.GridLines = flexGridFlat
pGrid.GridColorHeader = RGB_GRAY
pGrid.GridLinesFixed = flexGridFlat
' ########################################################################################
' Microsoft Windows
' Contents: Embedded Microsoft Hierarchical Grid Control
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2026 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 _CAXH_DEBUG_ 1
#INCLUDE ONCE "AfxNova/AfxCOM.inc"
#INCLUDE ONCE "AfxNova/CAxHost.inc"
#INCLUDE ONCE "AfxNova/MSHFlexGrid.inc"
#INCLUDE ONCE "AfxNova/CADODB.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)
' // Forward declaration
DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
CONST IDC_GRID = 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
' // The recommended way is to use a manifest file
AfxSetProcessDPIAware
' // Creates the main window
DIM pWindow AS CWindow
' -or- DIM pWindow AS CWindow = "MyClassName" (use the name that you wish)
DIM hwndMain AS HWND = pWindow.Create(NULL, "Microsoft Hierarchical Flex Grid", @WndProc)
' // Sizes it by setting the wanted width and height of its client area
pWindow.SetClientSize(800, 450)
' // Centers the window
pWindow.Center
DIM wszLibName AS WSTRING * 260 = ExePath & "\MSHFLXGD.OCX"
DIM pHost AS CAxHost = CAxHost(@pWindow, IDC_GRID, wszLibName, AFX_CLSID_MSHFlexGrid, _
AFX_IID_IMSHFlexGrid, RTLKEY_MSHFlexGrid, 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
pWindow.AnchorControl(IDC_GRID, AFX_ANCHOR_HEIGHT_WIDTH)
SetFocus pHost.hWindow
DIM pGrid AS CMSHFlexGrid = pHost.OcxDispObj
' // Set the width of the columns (in twips)
pGrid.ColWidth(0) = 300
pGrid.ColWidth(1) = 1100
pGrid.ColWidth(2) = 3000
pGrid.ColWidth(3) = 2000
pGrid.ColWidth(4) = 2000
pGrid.ColWidth(5) = 3000
pGrid.ColWidth(6) = 1500
pGrid.ColWidth(7) = 700
pGrid.ColWidth(8) = 1200
pGrid.ColWidth(9) = 1200
pGrid.ColWidth(10) = 1500
pGrid.ColWidth(11) = 1500
' Change the foreground and background colors
pGrid.ForeColor = BGR(0, 0, 0)
pGrid.BackColor = BGR(255,255,235)
' Open an ADO connection
DIM pConnection AS CAdoConnection PTR = NEW CAdoConnection
pConnection->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & ExePath & $"\nwind.mdb"
pConnection->Open
' Open a recordset
DIM pRecordset AS CAdoRecordset PTR = NEW CAdoRecordset
DIM dvSource AS DVARIANT = "SELECT * FROM Customers"
pRecordset->Open(dvSource, pConnection, adOpenKeyset, adLockOptimistic, adCmdText)
' Set the Datasource property of the recordset
pGrid.DataSource = cast(ANY PTR, pRecordset->DataSource)
' Close the recordset
pRecordset->Close
' Close the connection
pConnection->Close
' // Delete the recordset
Delete pRecordset
' // Delete the connection
Delete pConnection
' // Display the window
ShowWindow(hwndMain, nCmdShow)
UpdateWindow(hwndMain)
' // Dispatch Windows messages
DIM uMsg AS MSG
WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
IF AfxCAxHostForwardMessage(GetFocus, @uMsg) = FALSE THEN
IF IsDialogMessageW(hwndMain, @uMsg) = 0 THEN
TranslateMessage(@uMsg)
DispatchMessageW(@uMsg)
END IF
END IF
WEND
FUNCTION = uMsg.wParam
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)
RETURN 0
' // Theme has changed
CASE WM_THEMECHANGED
AfxEnableDarkModeForWindow(hwnd)
RETURN 0
CASE WM_COMMAND
SELECT CASE LOWORD(wParam)
CASE IDCANCEL
' // If ESC key pressed, close the application by sending an WM_CLOSE message
IF HIWORD(wParam) = 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
' ========================================================================================
' // Dispatch Windows messages
DIM uMsg AS MSG
WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
IF AfxCAxHostForwardMessage(GetFocus, @uMsg) = FALSE THEN
IF IsDialogMessageW(hwndMain, @uMsg) = 0 THEN
TranslateMessage(@uMsg)
DispatchMessageW(@uMsg)
END IF
END IF
WEND
QuoteSince FreeBASIC does not provide a separate data type for UTF-8 (it only has STRING), if you do not specify that it is UTF‑8 or CP_UTF8, the constructor will assume you are passing an ANSI string and use the CP_ACP code page to process it. Keep in mind that all characters in a UTF-8 string are treated as ANSI characters.Thanks again.
QuoteCheck this option: Environment Options / Code Editor / "Click margin to toggle breakpoints instead of bookmarks".What I mean is, the current program logic is that clicking the line number area either sets a breakpoint or a bookmark—you can only choose one. Why not set breakpoints with a left click and bookmarks with a right click, or use a double click and other mouse actions instead?
PRIVATE FUNCTION DWSTRING.Add (BYREF ansiStr AS STRING, BYVAL nCodePage AS UINT = 0) AS BOOLEAN
DWSTRING_DP("STRING - buffer: " & ..WSTR(m_pBuffer) & " - codepage: " & ..WSTR(nCodePage))
IF .LEN(ansiStr) = 0 THEN RETURN FALSE
' // Create the wide string from the incoming ansi string
DIM dwLen AS UINT, pbuffer AS ANY PTR
DIM bRes AS BOOLEAN = TRUE ' // assume success for now
IF nCodePage = CP_UTF8 THEN ' // check if it is really valid utf-8
IF this.IsUtf8(ansiStr) = FALSE THEN nCodePage = CP_ACP
END IF
IF nCodePage = CP_UTF8 THEN
dwLen = MultiByteToWideChar(CP_UTF8, 0, STRPTR(ansiStr), -1, NULL, 0)
IF dwLen = 0 THEN RETURN FALSE
pbuffer = Allocate(dwLen * 2)
dwLen = MultiByteToWideChar(CP_UTF8, 0, STRPTR(ansiStr), -1, pbuffer, dwLen)
IF dwLen = 0 THEN bRes = FALSE
ELSE
dwLen = MultiByteToWideChar(nCodePage, MB_PRECOMPOSED, STRPTR(ansiStr), -1, NULL, 0)
IF dwLen = 0 THEN RETURN FALSE
pbuffer = Allocate(dwLen * 2)
dwLen = MultiByteToWideChar(nCodePage, MB_PRECOMPOSED, STRPTR(ansiStr), -1, pbuffer, dwLen)
IF dwLen = 0 THEN bRes = FALSE
END IF
IF bRes = FALSE THEN
IF pBuffer THEN Deallocate(pbuffer)
RETURN bRes
END IF
' // Copy the string into the buffer
IF pbuffer THEN
' Copy the string into the buffer and update the length
bRes = this.AppendBuffer(pbuffer, dwLen)
' // Deallocate the buffer
IF pBuffer THEN Deallocate(pbuffer)
END IF
RETURN bRes
END FUNCTION
IF nCodePage = CP_UTF8 THEN ' // check if it is really valid utf-8
IF this.IsUtf8(ansiStr) = FALSE THEN nCodePage = CP_ACP
END IF
Quote from: fbfans on February 20, 2026, 01:16:03 PMI'm just not entirely sure why this became a problem in the first place.It is a well known Tiko parsing problem. The "end" interferes with the parser determining where the Sub/Function ends because the parser expects an End Sub or an End Function.
Quote1、Regarding the function list for files: Shouldn't clicking on it allow you to expand or collapse the list for each file? Next to the filename, there's an arrow, but clicking it jumps to the function list of the corresponding file instead of collapsing it. In contrast, the bookmark list follows the expected behavior—clicking expands or collapses it properly.Yes, you're probably right about this one. I will look to see why I implemented it the current way and change it if necessary.
Quote2、The scrollbar's drag activation area is too narrow. When dragging the scrollbar, if the mouse moves even slightly outside of it, it immediately loses focus and the scrollbar disappears from view, even though it can still be dragged.This was actually fixed (finally) yesterday. See this post: https://www.freebasic.net/forum/viewtopic.php?p=310481#p310481
Quote3、Regarding bookmarks: Normally, when a bookmark is set, it should appear in the sidebar's bookmark tab. Currently, only bookmarks set via Ctrl+F2 appear automatically. Bookmarks set with the mouse do not—they only show up if I click the "..." next to the sidebar bookmarks and select "Expand All."Yes, there does seem to be something strange going on there.
QuoteIn your version 1.3 update, you added the option to set breakpoints. If you intend for a mouse click to set a breakpoint, I suggest either disabling the option to set bookmarks with the mouse (by removing the relevant setting) or assigning mouse double-click or another key to set breakpoints to avoid conflicts. Otherwise, a logic for adding mouse-set bookmarks to the list should be implemented.Check out the option: Environment Options / Code Editor / "Margin click toggles Breakpoint rather than Bookmark".
QuoteAdditionally, I revisited the translation and am unsure if "clear bookmarks" in the sidebar and menu bar are meant to have the same meaning. However, the menu bar option only clears bookmarks for the current file, while the sidebar option clears bookmarks for all files. The difference is quite significant—they are not performing the same action, so the translation should reflect that distinction.Clicking the "..." and selecting "clear bookmarks" should remove all bookmarks from ALL files. Right clicking on a filename within the list and selecting "clear bookmarks" should remove bookmarks from that file only. Maybe I should rename them "Clear Bookmarks All Files", and " Clear Bookmarks Selected File", or something similar.
dim as dwstring txt = "围棋"
plutovg_text(pluto, txt.utf8, 32, 128)
plutovg_fill(pluto)
2. When source file is UTF‑8dim as dwstring txt = "你好 围棋"
plutovg_text(pluto, txt.utf8, 330, 128)
plutovg_fill(pluto)
I have to use this instead to display properly:DIM AS DWSTRING dtxt = dwstring("你好 围棋", CP_UTF8)
plutovg_text(pluto, dtxt.utf8, 330, 128)
plutovg_fill(pluto)
From an earlier example:QuoteUtf8ToAnsiMy questions:
DIM dws AS DWSTRING = DWSTRING(utf8Str, CP_UTF8)
DIM ansiStr AS STRING = dws
#define unicode
#include "plutovg.bi"
#include "afxnova/Dwstring.inc"
using afxnova
' draw vector font's on FBGFX Image
const as long iWidth = 640
const as long iHeight = 480
const as double FONT_SIZE = 40
screenres iWidth,iHeight,32
var img = ImageCreate(iWidth, iHeight, 0)
dim as ubyte ptr imgPixels
dim as long imgWidth,imgHeight,imgBytes,imgPitch
ImageInfo(img, imgWidth, imgHeight, imgBytes, imgPitch, imgPixels)
var surface = plutovg_surface_create_for_data(imgPixels,imgWidth,imgHeight,imgPitch)
var pluto = plutovg_create(surface)
var font = plutovg_font_load_from_file("c:/windows/fonts/simhei.ttf",FONT_SIZE)
plutovg_set_font(pluto,font)
plutovg_set_source_rgb(pluto, 1, 1, 0)
dim as wstring * 8 txt = "你好 世界"
plutovg_text(pluto, txt, 20, 128)
'plutovg_fill(pluto)
DIM AS DWSTRING dtxt = dwstring("你好 围棋", CP_UTF8)
plutovg_text(pluto, dtxt.utf8, 330, 128)
plutovg_fill(pluto)
plutovg_text(pluto, txt, 32, 256)
plutovg_text(pluto, "你好 中国", 330, 256)
plutovg_stroke(pluto)
plutovg_save(pluto)
plutovg_text(pluto, txt, 90, 344)
plutovg_text(pluto, dtxt.utf8, 390, 344)
plutovg_rotate(pluto,.2)
plutovg_fill(pluto)
plutovg_restore(pluto)
put (0,0),img,PSET 'ALPHA
sleep
plutovg_surface_destroy(surface)
plutovg_destroy(pluto)
plutovg_font_destroy(font)