Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions WIP.Assert.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Assert Package — Working Notes

See [WIP.md](WIP.md) for the cross-package maintenance guide.

Three sibling modules — `Exact`, `Strict`, `Permissive` — that expose the **same 15-member API**; only the comparison semantics differ:

| Module | String comparisons | Other comparisons |
|---------------|--------------------|--------------------------------------------------------------------------------|
| `Exact` | case-sensitive | no implicit conversions; datatypes must match exactly (`5 <> 5.0`); `vbNullString <> ""`; `Empty` distinct from `0` / `False` / `""`; object default members **not** evaluated |
| `Strict` | case-sensitive | evaluated as if written directly in twinBASIC; object default members **not** evaluated |
| `Permissive` | case-insensitive | evaluated as if written directly in twinBASIC |

`Null` is never equal to anything (not even itself) under any of the three flavours — use `IsNull` / `IsNotNull` to test for it.

The 15 members per module (identical signatures across all three):

| Member | Purpose |
|-------------------------------------------------|------------------------------------------------------------------|
| `Succeed()` | unconditionally records a pass |
| `Fail([Message])` | unconditionally records a failure |
| `Inconclusive([Message])` | records an inconclusive / skipped result |
| `AreEqual(Expected, Actual, [Message])` | value-equality assertion |
| `AreNotEqual(Expected, Actual, [Message])` | inverse of `AreEqual` |
| `AreSame(Expected, Actual, [Message])` | reference-identity (`Is`) assertion for objects |
| `AreNotSame(Expected, Actual, [Message])` | inverse of `AreSame` |
| `IsTrue(Condition, [Message])` | asserts the condition is `True` |
| `IsFalse(Condition, [Message])` | asserts the condition is `False` |
| `IsNothing(Value, [Message])` | asserts the object reference is `Nothing` |
| `IsNotNothing(Value, [Message])` | inverse of `IsNothing` |
| `IsNull(Value, [Message])` | asserts the value is `Null` |
| `IsNotNull(Value, [Message])` | inverse of `IsNull` |
| `SequenceEquals(Expected, Actual, [FailMessage])` | element-by-element comparison of two sequences / arrays |
| `NotSequenceEquals(Expected, Actual, [FailMessage])` | inverse of `SequenceEquals` |

Surface each member as if it were an ordinary `Sub` (e.g. `Sub AreEqual(Expected, Actual, [Message])`); the source-side `Lib "<assert{exact,strict,permissive}>"` / `Alias "#N"` / `PreserveSig` / `DeclareWide` decoration is internal pseudo-DLL plumbing and is **not** surfaced. Call out `[DebugOnly(True)]` (assertions compile out of release builds) and `[MustBeQualified(True)]` (callers must write the module name, e.g. `Strict.IsTrue(x)`).

Layout: one page per module, listing all 15 members inline under `## <Member>` headings (deep-linkable as `…/Strict#areequal`). Replicating 15 × 3 = 45 near-duplicate pages would add noise without value.
48 changes: 48 additions & 0 deletions WIP.CEF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# CEF Package — Working Notes

See [WIP.md](WIP.md) for the cross-package maintenance guide.

The entire user-facing surface lives in one source file (`CefControl.twin`): the private `CefBrowserBaseCtl` (where every event / method / property is declared), the private `CefEnvironmentOptions`, and the public `CefBrowser` control which inherits from `CefBrowserBaseCtl`. Everything else under the source tree (`CefControlGlobalWnd`, `APIs`, `MainModule`, `Registry`, `SpecialFolders`, the `CEF\Aliases` / `ApiEntryPoints` / `Globals` / `Initialize` / `Misc` modules, the 30 `_cef_*_t` internal enums and structs, the `CrossProcessIPC` IPC brokers, and every `Implementations/*` callback handler) is `Private Class` / `Private Module` plumbing and gets no doc page. Two user-facing enums live inside otherwise-private files: `CefLogSeverity` in the `_cef_log_severity_t` enum file, and `cefPrintOrientation` inline in `BrowserOM.twin`.

Public user-facing surface (one control + one options class + two enums):

| Symbol | Kind | Role |
|------------------------------|---------------------------------------|-----------------------------------------------------------------------------------------------|
| `CefBrowser` | Class (inherits `CefBrowserBaseCtl`) | the control itself, tagged `[WindowsControl("/Miscellaneous/cef64.png")]` |
| `CefEnvironmentOptions` | `Private Class`, exposed | reached via `Public EnvironmentOptions As CefEnvironmentOptions = New CefEnvironmentOptions` on the control |
| `CefLogSeverity` | `Enum` (in `_cef_log_severity_t.twin`)| used by `CefEnvironmentOptions.LogSeverity` |
| `cefPrintOrientation` | `Enum` (in `BrowserOM.twin`) | used by the `Orientation` parameter of `CefBrowser.PrintToPdf` |

`CefBrowserBaseCtl` is `Private Class` but is where every public member is *declared* — `CefBrowser` itself adds nothing beyond inheriting from it. The page (`CefBrowser/index.md`, folder-style, parallel to `WebView2/`) describes the union; the base class is invisible to user code.

`CefBrowser` inherits from `VB.BaseControlRectDockable`, so its Properties listing folds in the dockable-rect surface (`Name`, `Left`, `Top`, `Width`, `Height`, `Anchors`, `Dock`, ...) the same way VB-package and CustomControls control pages do.

`CefBrowserRequestHeaders` is declared as `Alias CefBrowserRequestHeaders As Object` and appears in the `NavigationStarting` event signature. The underlying `Class CefRequestHeaders` is an empty placeholder for a future header collection. **No doc page;** mention on the `NavigationStarting` event entry that the parameter is currently typed `Object` and reserved for future use.

The `CefBrowser` public surface:

- **Events (12):** `Create`, `Ready`, `Error`, `NavigationStarting`, `NavigationComplete`, `SourceChanged`, `DocumentTitleChanged`, `DOMContentLoaded`, `PrintToPdfCompleted`, `PrintToPdfFailed`, `JsAsyncResult`, `JsMessage`.
- **Methods (14):** `Initialize`, `Navigate`, `NavigateToString`, `Reload`, `GoBack`, `GoForward`, `ExecuteScript`, `JsRun`, `JsRunAsync`, `PostWebMessage`, `SetVirtualHostNameToFolderMapping`, `ClearVirtualHostNameToFolderMapping`, `OpenDevToolsWindow`, `PrintToPdf`.
- **Properties (12):** `DocumentURL` (Get/Let), `DocumentTitle` (Get), `ZoomFactor` (Get/Let), `UserAgent` (Get/Let), `CanGoBack` (Get), `CanGoForward` (Get), `CefMajorVersion` (Get), `Visible` (Get/Let), `hWnd` (Get), `Parent` (Get), `EnvironmentOptions` (field), `CreateInitialized` (field, `Boolean`, defaults `True`). Plus a `Hidden` `Align` (Get/Let) inherited boilerplate. Plus the inherited rect-dockable surface (`Name`, `Left`, `Top`, `Width`, `Height`, `Anchors`, `Dock`, …).

`CefEnvironmentOptions` is four bare `Public` fields:

| Field | Type |
|----------------------------|------------------|
| `BrowserExecutableFolder` | `String` |
| `UserDataFolder` | `String` |
| `LogFilePath` | `String` |
| `LogSeverity` | `CefLogSeverity` |

`CefLogSeverity` members: `CefLogDisable = 0`, `CefLogVerbose = 1`, `CefLogInfo = 2`, `CefLogWarning = 3`, `CefLogError = 4`, `CefLogFatal = 5`.

`cefPrintOrientation` members: `cefPrintPortrait = 0`, `cefPrintLandscape = 1`.

**WebView2-parity gap list** (called out on `CEF/index.md`, drawn from the sample-project examples where these are commented out as *"Sorry, this feature is not yet available in the CEF package"*):

- Methods: `OpenTaskManagerWindow`, `AddObject` (host-object publication), the request-filter machinery (`AddWebResourceRequestedFilter`).
- Events: `AcceleratorKeyPressed`, `PermissionRequested`, `WebResourceRequested`, `ProcessFailed`, `ScriptDialogOpening`, `UserContextMenu`, `SuspendCompleted`, `SuspendFailed`, `DownloadStarting`, `NewWindowRequested`.

`CefBrowser.NavigationComplete` carries `IsSuccess` and `WebErrorStatus` parameters, but `OnNavigationComplete_UI` currently hard-codes `IsSuccess = True` and `WebErrorStatus = 0` with `FIXME` comments — noted on the event entry.

**Multi-version source.** The same `.twin` sources compile against three CEF runtimes (v49 / v109 / v145) selected via the `CEF_VERSION` conditional-compilation argument on the project. At runtime, `CefBrowser.CefMajorVersion` returns the value picked at compile time. The user picks a runtime at deploy time by downloading the matching ZIP from `github.com/twinbasic/cef-runtimes` and extracting to `%LocalAppData%\twinBASIC_CEF_Runtime\`, or by overriding `CefBrowser.EnvironmentOptions.BrowserExecutableFolder` before / during the `Create` event. The runtime download + version-picking section lives on `CEF/index.md`.
81 changes: 81 additions & 0 deletions WIP.CustomControls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# CustomControls Package — Working Notes

See [WIP.md](WIP.md) for the cross-package maintenance guide.

Two source-side packages, **one** doc-side package (`docs/Reference/CustomControls/`). The two source halves split by *role*: a **DESIGNER** framework (the abstract surface a custom control hooks into — `ICustomControl`, `ICustomForm`, the `CustomControlContext` / `CustomFormContext` / `CustomControlTimer` / `CustomControlsCollection` CoClasses, plus the `SerializeInfo` / `Canvas` UDTs and the enums) and a **runtime** half (the eight concrete `Waynes…` controls + shared appearance helpers + mixin base classes).

Public user-facing surface, grouped by role.

## Concrete controls

Each is `Class <Name>` (no `Public` modifier — implicitly public), tagged `[CustomControl("/miscellaneous/frm<X>.png")]` (designer icon) and `[COMCreatable(False)]` (cannot be `New`'d through COM; instantiated by the designer).

| Control | Implements | Co-located public types |
|------------------|-----------------------------------------------------------|--------------------------------------------------|
| `WaynesButton` | `ICustomControl` + `BaseControlFocusable` (mixin) | `WaynesButtonState` (private, but exposed) |
| `WaynesForm` | `ICustomControl` + `BaseForm` (mixin) | — (uses `WindowsFormOptions` from support file) |
| `WaynesFrame` | `ICustomControl` + `BaseControl` (mixin) | — |
| `WaynesGrid` | `ICustomControl` + `BaseControlFocusable` (mixin) | `Column`, `CellRenderingOptions` |
| `WaynesLabel` | `ICustomControl` + `BaseControl` (mixin) | — |
| `WaynesSlider` | `ICustomControl` + `BaseControlFocusable` (mixin) | `WaynesSliderState`, `SliderDirection` & `SliderDisplayValueFormat` (nested enums) |
| `WaynesTextBox` | `ICustomControl` + `BaseControlFocusable` (mixin) | `WaynesTextBoxState` |
| `WaynesTimer` | `ICustomControl` + `BaseControl` (mixin) | — |

The "mixin" base classes (`BaseControl`, `BaseControlFocusable`, `BaseForm`) are pulled into each control via the twinBASIC `Implements <Base> Via _BaseControl = New <Base>` syntax. The base classes themselves get **no doc page** (they're private and never named by user code), but the inherited members **must be folded into each control's Properties listing** the same way VB-package controls list their inherited surface. The visible inherited surface, by mixin:

- `BaseControl` → `Name`, `Left`, `Top`, `Width`, `Height`, `Anchors`, `Dock`, `Visible`.
- `BaseControlFocusable` → all of `BaseControl` + `TabIndex`, `TabStop`.
- `BaseForm` → `FormDesignerId`, `Name`, `Left`, `Top`, `Width`, `Height`, `Controls`.

The state-holder classes (`WaynesButtonState`, `WaynesSliderState`, `WaynesTextBoxState`) and `WindowsFormOptions` are declared `Private Class` but are exposed on the parent control via `Public WithEvents NormalState As WaynesButtonState` (etc.). Same situation as `WebView2EnvironmentOptions` — document them as **sub-pages** of the parent control using the folder-style layout.

## Shared appearance helpers

These helpers are reachable through `Public WithEvents …` properties on one or more of the eight controls:

| Class | Reached as |
|-----------------|-------------------------------------------------------------------------------------|
| `Anchors` | `<control>.Anchors` (via the mixin base) |
| `Corners` | `<state>.Corners`, `CellRenderingOptions.Corners`, `<sliderState>.BackgroundCorners`, `BlockCorners` |
| `Corner` | `Corners.TopLeft` / `.TopRight` / `.BottomLeft` / `.BottomRight` |
| `Borders` | `<state>.Borders`, `CellRenderingOptions.Borders`, `<sliderState>.BackgroundBorders`, `BlockBorders` |
| `Border` | element of `Borders.Elements()`; also `TextRendering.Outlines()` |
| `Fill` | `<state>.BackgroundFill`, `<sliderState>.BlockFill`, `CellRenderingOptions.Fill`, `Border.Fill`, `Line.Fill`, `TextRendering.Fill` |
| `FillColorPoint` | element of `FillColorPoints.Values()` |
| `FillColorPoints` | `Fill.ColorPoints` |
| `Line` | `WaynesGrid.VerticalLineOptions` / `.HorizontalLineOptions` / `.ResizerBar` |
| `Padding` | `TextRendering.Padding` |
| `TextRendering` | `<state>.TextRendering`, `WaynesLabel.TextRendering`, `CellRenderingOptions.TextRendering` |
| `FontStyle` | `TextRendering.Font` |
| `WindowsFormOptions` | `WaynesForm.WindowsOptions` (only one consumer) |

These pair their small helpers on a single page (`Corner` inlines under `Corners.md`, `Border` under `Borders.md`, `FillColorPoint` and `FillColorPoints` under `Fill.md`, `FontStyle` under `TextRendering.md`). `WindowsFormOptions` is the exception: it has exactly one consumer (`WaynesForm`), so it sits as a folder-style sub-page of `WaynesForm/`, parallel to how WebView2 carries `EnvironmentOptions`. The `TextDecorator(s)` / `UDTs` / `MathSupport` / `ColorSupport` / mixin-bases content is package-internal and gets **no doc page**.

## DESIGNER framework surface

The framework half — what a *control author* writes against. Documented under `docs/Reference/CustomControls/Framework/`:

| Symbol | Kind | Role |
|------------------------------|---------------------|---------------------------------------------------------------------------------------|
| `ICustomControl` | `Interface` | what every concrete control implements: `Initialize(Context)`, `Destroy()`, `Paint(Canvas)` |
| `ICustomForm` | `Interface` | analogous surface for form-class custom controls |
| `CustomControlContext` | `CoClass` | passed to `ICustomControl.Initialize`; offers `GetSerializer()`, `Repaint()`, `CreateTimer()`, `ChangeFocusedElement()` |
| `CustomFormContext` | `CoClass` | extends `CustomControlContext` with `Show()` / `Close()` |
| `CustomControlTimer` | `CoClass` | returned by `CustomControlContext.CreateTimer()`; `Interval`, `Enabled`, `OnTimer` event |
| `CustomControlsCollection` | `CoClass` | the `Controls` collection on a form — `Count`, `Item`, `Add`, `Remove`, `_NewEnum` |
| `SerializeInfo` | UDT | obtained from `Context.GetSerializer()`; exposes `RuntimeUISrz*` operations (deserialize, mode flags, …) |
| `Canvas` | UDT | parameter to `ICustomControl.Paint`; exposes `RuntimeUICCCanvasAddElement` + DPI / size getters |

Both UDTs follow a pattern unique to twinBASIC: a `Pointer As LongPtr` field plus `Public DeclareWide PtrSafe Function/Sub … Lib "<runtimeuisrz>" Alias "#N"` pseudo-DLL declarations bound directly into the type. From a *caller* perspective these read as instance methods on the UDT (`Canvas.RuntimeUICCCanvasAddElement(descriptor)`); document them as methods, and **do not** surface the `Lib "<…>"` / `Alias "#N"` / `PreserveSig` / `DLLStackCheck` decoration (same treatment as Assert's pseudo-DLL plumbing). The verbose `RuntimeUISrz*` / `RuntimeUICC*` names are unfortunate but they *are* the public API — keep them as-is.

The two underscore-prefixed default interfaces of each CoClass (`_CustomControlTimer`, `_CustomControlContext`, `_CustomFormContext`, `_CustomControlsCollection`, `_CustomControlTimerEvents`) are an implementation detail of the COM `[Default]`/`[Default, Source]` pattern — fold their members onto the CoClass page, **don't** give the interfaces their own pages.

## Enumerations

Public enums under `docs/Reference/CustomControls/Enumerations/`:

- `CornerShape`, `FillPattern`, `TextAlignment`, `TextOverflowMode`, `DockMode`, `FontWeight`, `StartupPosition`, `BorderStyle`, `WindowState` — straightforward value enums.
- `Customtate` — **probable typo** for `CustomState`. Has the same three members as `WindowState` (`tbNormal` / `tbMinimized` / `tbMaximized`) and isn't referenced anywhere else in the package. Document it (since it's `Public`), but add a `> [!NOTE]` callout flagging the typo and pointing readers to `WindowState`.
- `ColorRGBA`, `PixelCount`, `PointSize` — these are declared as `Enum` only because twinBASIC doesn't yet have a `Type Foo = Long` alias syntax. Each carries a `FIXME` comment ("Substitute for an ALIAS to Long") and a single `[_MAX] = 0` placeholder member. Document them as **typedefs for `Long`** (the underlying storage type), not as real enums. Note in each that the alias is what user code actually sees on `Public Width As CustomControls.PixelCount` (etc.) — when the alias syntax lands, these enum stand-ins go away.

Plus the two enums nested inside `WaynesSlider`: `SliderDirection` and `SliderDisplayValueFormat`. They live on the `WaynesSlider/index.md` page rather than under `Enumerations/` (locally scoped to the slider).
Loading
Loading