# Copyright (c) 2025-2026 Gigasoft, Inc. All rights reserved. === ProEssentials Core Knowledge (knowledge rev 4.3) === ProEssentials is a .NET/C++ charting SDK with five chart objects. Each wraps a native Win32 DLL for high performance, exposed through a hierarchical .NET property interface. ALWAYS use pe_query.py to look up exact property paths, types, enum values, and method signatures before writing code. CHART OBJECTS (choose first, drives entire implementation): Pego -- Graph Object. Categorical/sequential X-axis. Bar, line, area, OHLC. X-axis labels via PointLabels array. Best for: dashboards, bar charts, financial OHLC, categorical data. Pesgo -- Scientific Graph Object. Continuous numeric X-axis. Scatter, line, area. Requires explicit X data array. Best for: scientific data, real-time streaming, XY scatter, time-series with irregular intervals. Pe3do -- 3D Scientific Graph. Surface plots, 3D scatter, wireframe, contour. Requires X, Y, Z data arrays. Pepso -- Polar/Smith Object. Polar coordinates, Smith charts, radar/spider plots. Pepco -- Pie Chart Object. Pie, doughnut, multi-ring charts. KEY ARCHITECTURAL CONCEPTS: 1) HIERARCHICAL PROPERTY INTERFACE All configuration is through nested property objects accessed from the chart: Pesgo1.PeData.___ (data arrays, counts, modes) Pesgo1.PePlot.___ (plotting method, visual options) Pesgo1.PeGrid.___ (axis scales, grid lines, zoom) Pesgo1.PeColor.___ (colors for all elements) Pesgo1.PeString.___ (labels, titles) Pesgo1.PeFont.___ (font sizing) Pesgo1.PeAnnotation.___ (line, graph, axis annotations) Pesgo1.PeUserInterface.___(interaction, cursors, hotspots, scrollbars) Pesgo1.PeConfigure.___ (rendering, prepare images, misc) Pesgo1.PeSpecial.___ (OHLC data, HObject handle, advanced) Pesgo1.PeFunction.___ (actions: reinitialize, print, zoom, export) Pesgo1.PeTable.___ (data table below chart) Pesgo1.PeLegend.___ (legend configuration) CRITICAL: Property NAMES within these groups are often abbreviated or shortened (e.g., the color for the desk area is PeColor.Desk, NOT PeColor.DeskColor). NEVER guess -- always query pe_query.py. 2) SUBSETS AND POINTS Data is organized as Subsets (series/lines) x Points (data values). Set PeData.Subsets and PeData.Points first, then populate PeData.Y[s,p]. Pego: X-axis is implicit (0,1,2...). Use PeString.PointLabels for labels. Pesgo: X-axis needs explicit PeData.X[s,p] values. 3) PROPERTY ARRAYS Large data arrays (Y, X, Z, SubsetColors, PointLabels, etc.) are special PropertyArray objects with methods like FastCopyFrom(), AppendData(), UseDataAtLocation(), BindData(). Use: pe_query.py methods "PeData.Y" ARRAY SIZE AND CONTROL: Property arrays are dynamic -- they grow as you set elements. Their size directly controls image construction behavior. Two categories exist: Empty by default (size=0): MultiAxesSubsets, OverlapMultiAxes, MultiAxesProportions, SubsetsToShow, SubsetsToLegend, Methods[]. These have NO effect when empty. They only activate when populated. Defaults defined (size>0): SubsetColors, SubsetLineTypes, SubsetPointTypes. These have pre-set values and work without explicit configuration. This distinction matters when reconfiguring a chart dynamically. An array that was populated must be explicitly cleared, otherwise old values persist. CLEARING ARRAYS: Use .Clear() to empty all elements in one call. Use .Clear(newSize) to trim. Essential when switching between chart modes or axis configurations: Pesgo1.PeGrid.MultiAxesSubsets.Clear(); // remove all axis assignments Pesgo1.PeGrid.OverlapMultiAxes.Clear(); Pesgo1.PeGrid.MultiAxesProportions.Clear(); Do NOT zero elements individually in a loop -- .Clear() is correct. INITIALIZING WITH A FILL VALUE: Initialize(value) fills the entire array with a scalar in one call. Useful to pre-fill data arrays with a null data sentinel before spoon-feeding: Pesgo1.PeData.Y.Initialize(-999f); // fill all with null value Set PeData.NullDataValue = -999 to match. See pe-nulldata. VIRTUAL LABELS: If PeString.PointLabels array is empty or has fewer items than PeData.Points, reading PointLabels[N] beyond the array range returns a string of "N+1" (e.g., PointLabels[0] returns "1", PointLabels[4] returns "5"). This auto-generation is called "VirtualLabels." It means the chart always has point labels even if none were explicitly set. GOTCHA: When building graph annotations (especially 3D polygon sequences), set the trailing annotation's Text = "" explicitly, otherwise VirtualLabels will produce unwanted numeric text at those annotation positions. 4) PER-DATAPOINT PROPERTIES vs GRAPH ANNOTATIONS PointColors and DataPointLabels are per-data-point properties tied to PeData.Y values -- they color or label individual Y data points within the chart's data model. PointColors is commonly used to color bars, points, or line segments based on data value, threshold, or category. DataPointLabels places custom text next to each data point. For scattered overlay items INDEPENDENT of chart data (markers, callouts, reference dots, icons), use PeAnnotation.Graph instead. Graph annotations are positioned at arbitrary X,Y coordinates and are not tied to subsets. Rule of thumb: coloring/labeling data --> PointColors/DataPointLabels. Overlay decorations independent of data --> GraphAnnotations. COLOR LIMIT: max 1024 DISTINCT colors across PointColors + SubsetColors (one cached brush per color; colors beyond 1024 are ignored). Reuse freely -- what counts is unique colors, not how many points use them. For heatmaps/gradients quantize the ramp: t = Math.Round(t * 191) / 191 -> at most 192 colors. 5) RENDERING PIPELINE PeConfigure.CacheBmp = true; -- ALWAYS SET on every chart. Caches rendered image in memory for flicker-free repainting. Without it, window overlap causes flicker. Direct2D/Direct3D RenderEngines force it true automatically. PeFunction.ReinitializeResetImage() -- full rebuild (data + image) PeFunction.ResetImage(0,0) -- image only rebuild (after visual changes) PeFunction.ReinitializeResetImage() is the standard refresh after data changes. PeFunction.Reinitialize() -- lighter rebuild (axis/layout only, no image reset). Use when changing ManualScaleControl or axis limits without data changes. Follow with Invalidate(). See pe-pe3do-patterns for details. PeData.ComputeShader = true -- enables GPU-side Direct3D construction on Pego, Pesgo, and Pe3do (RenderEngine.Direct3D required). Best for real-time and large datasets. See pe-pesgo-patterns and pe-pe3do-patterns for supported plotting methods, line type implications, and tuning. 6) BACKGROUND BITMAPS (all chart objects) Place a bitmap image behind the chart with three steps: a) PeColor.BitmapGradientMode = true; // MUST be set first b) PeColor.DeskBmpFilename = "path/to/image.jpg"; // desk area bitmap c) PeColor.DeskBmpStyle = BitmapStyle.StretchBlt; // large images PeColor.DeskBmpStyle = BitmapStyle.TiledBitBlt; // small/tileable images To see bitmap through graph area, make graph backgrounds transparent: PeColor.GraphBackground = Color.FromArgb(0,1,0,0); // PE "empty" color PeColor.GraphGradientStyle = GradientStyle.NoGradient; With multi-axis: set transparent background per axis via WorkingAxis loop. PE "empty" color convention: Color.FromArgb(0,1,0,0) means transparent/empty. Also available: GraphBmpFilename (graph area only), TableBmpFilename (table). DeskBmpOpacity (0-100) controls bitmap translucency. Query: pe_query.py search "BmpFilename" 7) ENUM-DRIVEN CONFIGURATION Most behavioral settings use enums. Never hardcode integer values. Query: pe_query.py enum "GraphPlottingMethod" Key enums: GraphPlottingMethod, SGraphPlottingMethod, ManualScaleControl, ViewingStyle, QuickStyle, RenderEngine, AllowZooming, MultiAxisStyle, DataShadows, CursorMode, CursorPromptStyle, MouseWheelFunction. CRITICAL -- PePlot.Method ENUM DIFFERS BY CHART OBJECT: The query tool reports PePlot.Method as type "GraphPlottingMethod" generically, but EACH chart object uses a DIFFERENT enum with DIFFERENT integer values. Using the wrong enum compiles but produces WRONG plotting at runtime. Pego --> GraphPlottingMethod (27 values, Point=2) Pesgo --> SGraphPlottingMethod (26 values, Point=1) Pepso --> PSGraphPlottingMethod (4 values: Line=0, Point=1, PointsPlusLine=2, Area=3) Pe3do --> ThreeDGraphPlottingMethod (5 values: Zero..Four, controls rendering quality) Pepco --> No PePlot.Method (pie charts have no plotting method enum) ALWAYS select the enum matching the chart object. Verify via base examples: Base 000: Pego1.PePlot.Method = GraphPlottingMethod.Area; Base 100: Pesgo1.PePlot.Method = SGraphPlottingMethod.PointsPlusSpline; Base 200: Pepso1.PePlot.Method = PSGraphPlottingMethod.PointsPlusLine; Base 400: Pe3do1.PePlot.Method = ThreeDGraphPlottingMethod.Zero; 8) APPLIES-TO FILTERING Properties apply to specific chart objects. pe_query.py shows this as Pg|Sg|3D|Po|Pi codes. A property that shows "Pg|Sg" works on Pego and Pesgo but not Pe3do, Pepso, or Pepco. 9) THREE API LAYERS (interchangeable) .NET: Pesgo1.PeData.Subsets = 5; DLL: PEnset(hObject, PEP_nSUBSETS, 5); VBA: Pego1.Subsets = 5 All three access the same engine. .NET is standard for C#/VB. DLL is used for MFC, special cases, or C++ native. .NET PeSpecial.HObject provides the DLL handle. VBA OCX Pego1.hObject provides DLL handle. C++ DLL REFERENCE: For MFC/Win32 C++ code, see pe-cpp-api-reference (~17K tokens, add only when writing pure DLL C++ code) for all PEP_ property constants, PEGAT_ annotation types, enum constants (PEMSC_*, PEQS_*, etc.), DLL function signatures, type prefix conventions, and the PERGB color macro. KEY RULE: 'a' in PEP_ prefix = array = use PEvsetcell. No 'a' = scalar = use PEnset. The .NET enum names do NOT match C++ constant names -- e.g., GraphAnnotationType.TopLeft is PEGAT_TOPLEFT. ALWAYS look up exact constants before writing DLL code. HELP FILE NAMING: HTM help files are named by the C++ property constant. Example: PEP_nSUBSETS -> PEP_nSUBSETS.htm in the help system. 10) LICENSING / EVAL NAG STRING Customers receive a serial number and matching key array (16 integers). The key must be applied via PEvsetW BEFORE any image render or WM_PAINT: int[] keys = { /* 16 integers from license */ }; Gigasoft.ProEssentials.Api.PEvsetW( Pesgo1.PeSpecial.HObject, 1798, keys, 16); // 64 bytes COMMON ISSUE: "Why does the eval string still show after installing with my serial number?" a) Key code must execute early -- before the chart renders its first image. If the chart receives WM_PAINT before the key is set, the eval nag persists for that session. b) If PeFunction.Reset / PEreset is called, the key must be re-applied immediately after the reset. In demo projects, add the PEvsetW key code just after PeFunction.Reset in the CreateAllChart functions (Form2, Form3, Form4, Form5, Form6). C++ DLL equivalent: int keys[] = { /* 16 integers */ }; PEvset(hObject, 1798, keys, 16); 11) OCX/VBA API LAYER (third interface, distinct from .NET and DLL) ActiveX/VCL users call methods directly on the control object. These have their own signatures, separate from .NET PeFunction.* equivalents: VBA method call: iPego1.GetRectGraph nLeft, nTop, nRight, nBottom .NET equivalent: Pego1.PeFunction.GetRectGraph(ref nL, ref nT, ref nR, ref nB) DLL equivalent: PExxx or no direct DLL equivalent in some cases uses PEvget & PEP_rectGRAPH VBA PROPERTY SYNTAX uses OCX constants, not .NET enum names: .NET: Pego1.PePlot.Method = GraphPlottingMethod.Point VBA: iPego1.PlottingMethod = GPM_POINT .NET: Pego1.PeUserInterface.Cursor.Mode = CursorMode.DataCross VBA: iPego1.CursorMode = PECM_DATACROSS The OCX constant names (PEQS_*, PECM_*, PEGAT_*, PELT_*, etc.) match the DLL PEP_ values but use shorter prefixes. NEVER use .NET enum names in VBA. SCOPE CONSTRAINT: OCX methods are not universal across all 5 chart objects. Unlike .NET properties that show appliesTo, OCX method scope is fixed: All 5 objects: GetLastMouseMove, GetHotSpotData, PEreinitialize, PEresetimage, PEcopy*, PElaunch*, PEprint*, PEdrawtable, GetRectTA Pego/Pesgo/Pepso: GetRectGraph, PEconvpixeltograph, PEpartialresetimage, GetRectAxis, GetGraphLoc Pego/Pesgo only: GetExtraAxisX, GetFallDayLight, SetFallDayLight Pe3do only: DxSetLight, DxGetLight 116 VBA examples are available (one per C#/C++ example, same example IDs). Access via: pe_query.py example --lang vba VBA examples show OCX method calls, event handlers, and constant usage reflecting real working code from the ProEssentials demo application. 12) .NET INTERFACES (WinForms, WPF, WinUI) -- SAME API, DIFFERENT TYPE NAMES The five chart objects ship as three .NET control sets. The PExxx property paths are IDENTICAL across all three; only the control TYPE name changes: WinForms Pego Pesgo Pe3do Pepso Pepco WPF PegoWpf PesgoWpf Pe3doWpf PepsoWpf PepcoWpf WinUI PegoWinUI PesgoWinUI Pe3doWinUI PepsoWinUI PepcoWinUI Pesgo1.PeData.Subsets = 5; is correct on all three, but the declared type (and the XAML element name) must carry the right suffix. IMPORTANT: pe_query.py is built from the WinForms assembly and does NOT index anything in this section. "No results" for these names does not mean they are missing. See pe-tool-instructions. BUILT-IN UX TOGGLE -- NAME DIFFERS PER INTERFACE (control-level, default true) WinForms Pesgo1.UseWinformsUX = false; WPF Pesgo1.UseWpfUX = false; WinUI Pesgo1.UseWinUIUX = false; Master switch for the v11 .NET UX. True gives the new .NET right-click menu and the new customize/export/print/maximize dialogs. False uses the entire LEGACY Win32 UX (the engine's native popup menu + native dialogs). The WinUI menu also avoids the native modal loop that can freeze real-time timers. WinUI ONLY: Pesgo1.RenderPriority = PeRenderPriority.Auto; // Auto|Low|Normal|High Dispatcher priority for the coalesced swap-chain renders. Auto (default) enqueues Low so a heavy or real-time chart yields to XAML work, but Normal while a mouse button is down (zoom-box pan, data-point drag) so dragging stays visually live. High can starve XAML input -- measure. Read on every render request, so it may change at any time, even mid-drag. Pesgo1.PeAnnotation.EnableWinUIDrawTable = true; // default false Opt in to the real-time DrawTable composition layer. Set true when the code calls PeFunction.DrawTable() for live table updates: the engine then keeps a dedicated transparent Direct2D layer so DrawTable repaints ONLY the table, not the whole chart. Left false, DrawTable still works, but via a full re-render. WinUI XAML HOSTING GOTCHA (host the chart cleanly): Do NOT put a Background on the Grid (or element) sitting BEHIND the chart. A Background behind the chart's swap chain can make the engine scrollbar render solid BLACK instead of the normal thin/overlay scrollbar (it repaints only while the pointer is over it, then reverts to black). Keep the chart's immediate container Background-free; if a side panel needs a color, set it on that panel, not on the container behind the chart. (Exact cause still under investigation; a thin scrollbar that fades to full on hover is NORMAL WinUI Fluent behavior, not this bug -- only a SOLID BLACK scrollbar indicates it.) WPF AND WinUI ONLY: Pesgo1.PersistenceEnabled = true; Pesgo1.PersistenceDataExists In-memory engine-state persistence across an Unloaded/Loaded of THIS control instance (tab switch, dock reparent, tab tear-out). State is snapshotted on teardown and reloaded on the next attach. It does NOT survive true destruction and is not cross-session. PersistenceDataExists is true when a snapshot exists, so a reload handler can skip rebuilding. ALL INTERFACES: PeGlobal.CacheBrand = "MyCompany"; // static, AnyCPU flavor only Names the per-user folder used when a self-contained AnyCPU assembly must extract its embedded native engine because the application folder is not writable (a Program Files install, or the Visual Studio designer). Path is %LOCALAPPDATA%\{CacheBrand}\ProEssentials\{version}\{arch}\. Leave it unset and the brand comes from the application's AssemblyCompany, falling back to "Gigasoft". Set once at startup before creating any chart. Ignored by the x64 and ARM64 flavors, which never extract an engine. WORKFLOW FOR WRITING CODE: 1. Choose chart object based on use case 2. Read relevant knowledge files for conceptual understanding 3. Query pe_query.py for EVERY property path, enum, and method 4. Use pe_query.py validate to verify all paths before final code 5. Query pe_query.py examples to find similar working examples