├── CNAME ├── LICENSE ├── README.md └── docs ├── CNAME ├── TEST.md ├── _config.yml ├── _data └── meta │ └── categories.json ├── _features └── index.md ├── _includes ├── breadcrumbs.html ├── lazyload.html └── toc.html ├── _intro └── index.md ├── _layouts └── default.html ├── _samples ├── customcontrols │ ├── ccCOMCreatable.png │ ├── ccClassIdAttribute.png │ ├── ccClassIdInsert.png │ ├── ccCustomControlAttribute.png │ ├── ccGridButtonImage.png │ ├── ccICustomControl.png │ ├── ccSampleProject.png │ ├── defining.md │ ├── formdesigner.md │ ├── index.md │ ├── painting.md │ └── propertysheetandserialization.md ├── index.md ├── packages │ ├── createpackage.md │ ├── importpackagefromfile.md │ ├── importpackagefromtwinserv.md │ ├── index.md │ └── updatepackage.md └── webview2 │ ├── index.md │ ├── reentrancy.md │ └── userdatafolder.md ├── assets ├── lazysizes.min.js └── treeview.css ├── images └── twinBASICIconTransparent.png ├── index.md ├── samples.md └── sitemap.xml /CNAME: -------------------------------------------------------------------------------- 1 | docs.twinbasic.com -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 twinbasic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # twinBASIC User Documentation 2 | General user documentation for twinBASIC 3 | 4 | - work in progress 5 | 6 | This repository is the home for general user documentation for everything to do with twinBASIC. The Wiki is the starting point: 7 | https://github.com/twinbasic/documentation/wiki 8 | 9 | If you want to get involved in improving the documentation, please fork the wiki, using the URL https://github.com/twinbasic/documentation.wiki.git, and submit pull requests for your suggested changes. 10 | 11 | All help is very much appreciated :) 12 | 13 | 14 | 15 | 16 | Wayne Phillips 17 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.twinbasic.com -------------------------------------------------------------------------------- /docs/TEST.md: -------------------------------------------------------------------------------- 1 | Another test 😅 2 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | url: twinbasic.github.io 2 | title: twinBASIC Documentation 3 | baseurl: / 4 | remote_theme: pages-themes/slate@v0.2.0 5 | markdown: redcarpet 6 | redcarpet: 7 | extensions: ["no_intra_emphasis", "tables", "autolink", "strikethrough", "with_toc_data", "disable_indented_code_blocks"] 8 | defaults: 9 | - scope: 10 | path: "" 11 | values: 12 | layout: default 13 | plugins: 14 | - jekyll-remote-theme 15 | collections: 16 | intro: 17 | output: true 18 | features: 19 | output: true 20 | samples: 21 | output: true -------------------------------------------------------------------------------- /docs/_data/meta/categories.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "category": "customcontrols", 4 | "title": "Custom Controls", 5 | "description": "Using custom controls in twinBASIC" 6 | }, 7 | { 8 | "category": "packages", 9 | "title": "Packages", 10 | "description": "Using packages in twinBASIC and TWINPACK server." 11 | }, 12 | { 13 | "category": "webview2", 14 | "title": "WebView2", 15 | "description": "Using WebView2 as a control in twinBASIC" 16 | } 17 | ] -------------------------------------------------------------------------------- /docs/_features/index.md: -------------------------------------------------------------------------------- 1 | This is tB features main page. -------------------------------------------------------------------------------- /docs/_includes/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_includes/lazyload.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | See: https://ranvir.xyz/blog/lazy-loading-your-images-in-jekyll-blog-improving-page-speed/ 3 | {% endcomment %} 4 | 5 | {% if include.image_src %} 6 | 7 | 8 | 9 | 10 | {{include.image_title}} 11 | {% endif %} -------------------------------------------------------------------------------- /docs/_includes/toc.html: -------------------------------------------------------------------------------- 1 | {% capture tocWorkspace %} 2 | {% comment %} 3 | Copyright (c) 2017 Vladimir "allejo" Jimenez 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | {% endcomment %} 26 | {% comment %} 27 | Version 1.2.0 28 | https://github.com/allejo/jekyll-toc 29 | 30 | "...like all things liquid - where there's a will, and ~36 hours to spare, there's usually a/some way" ~jaybe 31 | 32 | Usage: 33 | {% include toc.html html=content sanitize=true class="inline_toc" id="my_toc" h_min=2 h_max=3 %} 34 | 35 | Parameters: 36 | * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll 37 | 38 | Optional Parameters: 39 | * sanitize (bool) : false - when set to true, the headers will be stripped of any HTML in the TOC 40 | * class (string) : '' - a CSS class assigned to the TOC 41 | * id (string) : '' - an ID to assigned to the TOC 42 | * h_min (int) : 1 - the minimum TOC header level to use; any header lower than this value will be ignored 43 | * h_max (int) : 6 - the maximum TOC header level to use; any header greater than this value will be ignored 44 | * ordered (bool) : false - when set to true, an ordered list will be outputted instead of an unordered list 45 | * item_class (string) : '' - add custom class(es) for each list item; has support for '%level%' placeholder, which is the current heading level 46 | * submenu_class (string) : '' - add custom class(es) for each child group of headings; has support for '%level%' placeholder which is the current "submenu" heading level 47 | * base_url (string) : '' - add a base url to the TOC links for when your TOC is on another page than the actual content 48 | * anchor_class (string) : '' - add custom class(es) for each anchor element 49 | * skip_no_ids (bool) : false - skip headers that do not have an `id` attribute 50 | 51 | Output: 52 | An ordered or unordered list representing the table of contents of a markdown block. This snippet will only 53 | generate the table of contents and will NOT output the markdown given to it 54 | {% endcomment %} 55 | 56 | {% capture newline %} 57 | {% endcapture %} 58 | {% assign newline = newline | rstrip %} 59 | 60 | {% capture deprecation_warnings %}{% endcapture %} 61 | 62 | {% if include.baseurl %} 63 | {% capture deprecation_warnings %}{{ deprecation_warnings }}{{ newline }}{% endcapture %} 64 | {% endif %} 65 | 66 | {% if include.skipNoIDs %} 67 | {% capture deprecation_warnings %}{{ deprecation_warnings }}{{ newline }}{% endcapture %} 68 | {% endif %} 69 | 70 | {% capture jekyll_toc %}{% endcapture %} 71 | {% assign orderedList = include.ordered | default: false %} 72 | {% assign baseURL = include.base_url | default: include.baseurl | default: '' %} 73 | {% assign skipNoIDs = include.skip_no_ids | default: include.skipNoIDs | default: false %} 74 | {% assign minHeader = include.h_min | default: 1 %} 75 | {% assign maxHeader = include.h_max | default: 6 %} 76 | {% assign nodes = include.html | strip | split: ' maxHeader %} 92 | {% continue %} 93 | {% endif %} 94 | 95 | {% assign _workspace = node | split: '' | first }}>{% endcapture %} 114 | {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %} 115 | 116 | {% if include.item_class and include.item_class != blank %} 117 | {% capture listItemClass %} class="{{ include.item_class | replace: '%level%', currLevel | split: '.' | join: ' ' }}"{% endcapture %} 118 | {% endif %} 119 | 120 | {% if include.submenu_class and include.submenu_class != blank %} 121 | {% assign subMenuLevel = currLevel | minus: 1 %} 122 | {% capture subMenuClass %} class="{{ include.submenu_class | replace: '%level%', subMenuLevel | split: '.' | join: ' ' }}"{% endcapture %} 123 | {% endif %} 124 | 125 | {% capture anchorBody %}{% if include.sanitize %}{{ header | strip_html }}{% else %}{{ header }}{% endif %}{% endcapture %} 126 | 127 | {% if htmlID %} 128 | {% capture anchorAttributes %} href="{% if baseURL %}{{ baseURL }}{% endif %}#{{ htmlID }}"{% endcapture %} 129 | 130 | {% if include.anchor_class %} 131 | {% capture anchorAttributes %}{{ anchorAttributes }} class="{{ include.anchor_class | split: '.' | join: ' ' }}"{% endcapture %} 132 | {% endif %} 133 | 134 | {% capture listItem %}{{ anchorBody }}{% endcapture %} 135 | {% elsif skipNoIDs == true %} 136 | {% continue %} 137 | {% else %} 138 | {% capture listItem %}{{ anchorBody }}{% endcapture %} 139 | {% endif %} 140 | 141 | {% if currLevel > lastLevel %} 142 | {% capture jekyll_toc %}{{ jekyll_toc }}<{{ listModifier }}{{ subMenuClass }}>{% endcapture %} 143 | {% elsif currLevel < lastLevel %} 144 | {% assign repeatCount = lastLevel | minus: currLevel %} 145 | 146 | {% for i in (1..repeatCount) %} 147 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 148 | {% endfor %} 149 | 150 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 151 | {% else %} 152 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 153 | {% endif %} 154 | 155 | {% capture jekyll_toc %}{{ jekyll_toc }}{{ listItem }}{% endcapture %} 156 | 157 | {% assign lastLevel = currLevel %} 158 | {% assign firstHeader = false %} 159 | {% endfor %} 160 | 161 | {% assign repeatCount = minHeader | minus: 1 %} 162 | {% assign repeatCount = lastLevel | minus: repeatCount %} 163 | {% for i in (1..repeatCount) %} 164 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 165 | {% endfor %} 166 | 167 | {% if jekyll_toc != '' %} 168 | {% assign rootAttributes = '' %} 169 | {% if include.class and include.class != blank %} 170 | {% capture rootAttributes %} class="{{ include.class | split: '.' | join: ' ' }}"{% endcapture %} 171 | {% endif %} 172 | 173 | {% if include.id and include.id != blank %} 174 | {% capture rootAttributes %}{{ rootAttributes }} id="{{ include.id }}"{% endcapture %} 175 | {% endif %} 176 | 177 | {% if rootAttributes %} 178 | {% assign nodes = jekyll_toc | split: '>' %} 179 | {% capture jekyll_toc %}<{{ listModifier }}{{ rootAttributes }}>{{ nodes | shift | join: '>' }}>{% endcapture %} 180 | {% endif %} 181 | {% endif %} 182 | {% endcapture %}{% assign tocWorkspace = '' %}{{ deprecation_warnings }}{{ jekyll_toc -}} 183 | -------------------------------------------------------------------------------- /docs/_intro/index.md: -------------------------------------------------------------------------------- 1 | This is tB introduction -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | {% comment %} The HTML has been copied from https://github.com/pages-themes/slate/blob/master/_layouts/default.html {% endcomment %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% seo %} 13 | {% include head-custom.html %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 | {% if site.github.is_project_page %} 27 | View on GitHub 28 | {% endif %} 29 | 30 |

{{ site.title | default: site.github.repository_name }}

31 |

{{ site.description | default: site.github.project_tagline }}

32 | 33 | {% include breadcrumbs.html %} 34 | 35 | {% if site.show_downloads %} 36 |
37 | Download this project as a .zip file 38 | Download this project as a tar.gz file 39 |
40 | {% endif %} 41 |
42 |
43 | 44 | 45 |
46 |
47 | {% include toc.html html=content %} 48 | {{ content }} 49 |
50 |
51 | 52 | 53 | 61 | 62 | -------------------------------------------------------------------------------- /docs/_samples/customcontrols/ccCOMCreatable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/_samples/customcontrols/ccCOMCreatable.png -------------------------------------------------------------------------------- /docs/_samples/customcontrols/ccClassIdAttribute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/_samples/customcontrols/ccClassIdAttribute.png -------------------------------------------------------------------------------- /docs/_samples/customcontrols/ccClassIdInsert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/_samples/customcontrols/ccClassIdInsert.png -------------------------------------------------------------------------------- /docs/_samples/customcontrols/ccCustomControlAttribute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/_samples/customcontrols/ccCustomControlAttribute.png -------------------------------------------------------------------------------- /docs/_samples/customcontrols/ccGridButtonImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/_samples/customcontrols/ccGridButtonImage.png -------------------------------------------------------------------------------- /docs/_samples/customcontrols/ccICustomControl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/_samples/customcontrols/ccICustomControl.png -------------------------------------------------------------------------------- /docs/_samples/customcontrols/ccSampleProject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/_samples/customcontrols/ccSampleProject.png -------------------------------------------------------------------------------- /docs/_samples/customcontrols/defining.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Defining a custom control 3 | category: customcontrols 4 | order: 2 5 | --- 6 | 7 | # Defining a CustomControl 8 | 9 | A CustomControl is simply an ordinary twinBASIC class, with a few extra attributes and requirements. 10 | 11 | {% include toc.html content=page.content skip_toc=page.skip_toc%} 12 | 13 | _**TIP: It is highly advisable to look at and experiment with the sample project provided with twinBASIC before trying to implement your own CustomControl.**_ 14 | 15 | {% include lazyload.html image_src="ccSampleProject.png" image_title="CustomControl Sample Project" %} 16 | 17 | *** 18 | 19 | ## CustomControl() attribute 20 | 21 | {% include lazyload.html image_src="ccCustomControlAttribute.png" image_title="CustomControl attribute" %} 22 | 23 | This is a required attribute for all CustomControls. You must provide the relative path to an image file within your project that can be used to identify your control in the form designer toolbox. We recommend that you put the image file in the Miscellaneous folder in your project. 24 | 25 | {% include lazyload.html image_src="ccGridButtonImage.png" image_title="CustomControl GridImage Folder" %} 26 | 27 | *** 28 | 29 | ## ClassId() attribute 30 | 31 | {% include lazyload.html image_src="ccClassIdAttribute.png" image_title="CustomControl ClassId Attribute" %} 32 | 33 | This is a required attribute for all CustomControls. You must provide a unique CLSID (GUID) in order for the form engine to work with your control. 34 | 35 | _**TIP: if you enter ` [ ClassId () ] ` twinBASIC helps you out - just press the 'insert a randomly generated GUID' text:**_ 36 | 37 | {% include lazyload.html image_src="ccClassIdInsert.png" image_title="CustomControl ClassId auto-generate" %} 38 | 39 | *** 40 | 41 | ## COMCreatable() attribute 42 | 43 | {% include lazyload.html image_src="ccCOMCreatable.png" image_title="CustomControl COMCreatable attribute" %} 44 | 45 | This is an optional attribute, but it is usually advisable to set this attribute to False, as you don't need to instantiate CustomControls from external COM environments. 46 | 47 | *** 48 | 49 | ## Must implement ICustomControl 50 | 51 | {% include lazyload.html image_src="ccICustomControl.png" image_title="CustomControl ICustomControl interface" %} 52 | 53 | All CustomControls *must* implement CustomControls.ICustomControl. This interface currently has 3 methods that you must implement: 54 | 55 | ``` 56 | Sub Initialize(ByVal Context As CustomControlContext) 57 | ``` 58 | 59 | This method is called when your control is attached to a form. You must store the provided Context object in a class field as it offers a `Repaint()` method for informing the form engine that something in your control has changed and needs to be repainted. 60 | 61 | ``` 62 | Sub Destroy() 63 | ``` 64 | 65 | This method is called when your control is detached from a form. This allows an opportunity to break circular references so that your object instance can be destructed properly. The implementation for this can often be left empty provided you don't create circular references in objects. 66 | 67 | ``` 68 | Sub Paint(ByVal Canvas As Canvas) 69 | ``` 70 | 71 | This is the most interesting part for a CustomControl. As such, it gets its own section, see [Painting / drawing to your control](painting.html) 72 | 73 | *** 74 | 75 | ## Minimum set of properties 76 | 77 | As twinBASIC doesn't yet support inheritance, you must expose a set of common properties (class fields) for all CustomControls: 78 | 79 | ``` 80 | Public Name As String 81 | Public Left As CustomControls.PixelCount 82 | Public Top As CustomControls.PixelCount 83 | Public Width As CustomControls.PixelCount 84 | Public Height As CustomControls.PixelCount 85 | Public Anchors As Anchors = New Anchors 86 | Public Dock As CustomControls.DockMode 87 | Public Visible As Boolean 88 | ``` 89 | 90 | The form designer and the form engine work with these properties, so it is important to include them in your CustomControl class. 91 | 92 | Note that the form designer works with pixel values which are not DPI-scaled. So the Left/Top/Width/Height properties of your control do not reflect DPI scaling. For example, if your control has a width of 50 pixels, then at DPI 150%, then the actual drawing width is 75 pixels ( see [Painting / drawing to your control](painting.html) ). 93 | *** 94 | 95 | ## Must have a serialization constructor 96 | 97 | CustomControls *must* offer a serialization constructor: 98 | 99 | ``` 100 | Public Sub New(Serializer As SerializationInfo) 101 | ``` 102 | 103 | The passed in Serializer object offers a `Deserialize()` method that you call in order to load the properties that have been set for your control via the form designer. See [Property Sheet & Object Serialization](propertysheetandserialization.html) for further information. -------------------------------------------------------------------------------- /docs/_samples/customcontrols/formdesigner.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Form Designer 3 | category: customcontrols 4 | order: 3 5 | --- 6 | 7 | 8 | # Notes about the form designer 9 | For the painting of controls in the form designer, CustomControl instances are instantiated and then release immediately after painting has finished. -------------------------------------------------------------------------------- /docs/_samples/customcontrols/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | category: customcontrols 4 | order: 1 5 | --- 6 | 7 | ### Introduction 8 | 9 | twinBASIC now offers experimental support for CustomControls. CustomControls are implemented using the BASIC language, allowing implementers to design controls directly from the twinBASIC environment. 10 | 11 | A few highlights; 12 | - completely custom drawn controls, with no external or third-party dependencies (tiny footprint) 13 | - support 32-bit RGBA for full alpha-transparency 14 | - support high-DPI modes (per-monitor), requiring little thought whilst designing new controls 15 | - full debugging support via the usual twinBASIC integrated debugger 16 | - designed for efficiency so that supporting complex controls with hundreds of elements (e.g. a DataGrid with 100's of cells) is easily possible 17 | - designed for flexibility, allowing for curved corners, multiple borders, background gradients and much more 18 | - the form engine supports anchoring and docking without any considerations needed for CustomControl implementers 19 | - simple property sheet synchronization via the built-in form designer -------------------------------------------------------------------------------- /docs/_samples/customcontrols/painting.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Painting custom controls 3 | category: customcontrols 4 | order: 3 5 | --- 6 | 7 | # Painting / drawing to your control 8 | ### The ICustomControl.Paint method 9 | This is by far the most important method of a CustomControl. It tells the form engine exactly how you want it to render your control. 10 | 11 | _**TIP: It is highly advisable to look at and experiment with the sample project provided with twinBASIC before trying to implement your own CustomControl.**_ 12 | 13 | Private Sub OnPaint(ByVal Canvas As CustomControls.Canvas) _ 14 | Implements ICustomControl.Paint 15 | 16 | You are passed a Canvas object that offers the following methods: 17 | 18 | Canvas.Width As Long [Propert-Get] 19 | Canvas.Height As Long [Propert-Get] 20 | Canvas.Dpi As Long [Propert-Get] 21 | Canvas.DpiScaleFactor As Double [Propert-Get] 22 | Canvas.AddElement(Descriptor As ElementDescriptor) 23 | 24 | `Canvas.Width` and `Canvas.Height` are the absolute pixel sizes that your control is drawing to. Unlike your controls Width/Height properties that are not DPI-scaled, the `Canvas.Width` and `Canvas.Height` values **are** DPI-scaled. 25 | 26 | The `Canvas.Dpi` property represents the DPI setting in Windows. If no DPI scaling is in effect, this value is 96. For example, if you have scaling set at 150% on your monitor, then the `Canvas.Dpi` property will be 144. 27 | 28 | The `Canvas.DpiScaleFactor` property gives a floating point value representing the DPI scaling percentage. A value of 1 indicates no scaling. For example, if you have scaling set at 150% on your monitor, then the `Canvas.DpiScaleFactor` property will be 1.5. 29 | 30 | The `Canvas.AddElement` method is used for adding elements to your control. An *element* is considered to be something that the form-engine will render for you. For example, you might have a grid control that displays 100 cells at a time. Each of those cells would be an *element*. Elements can overlap each over (allowing for opacity/transparency). The form engine draws them in the order that you call AddElement, meaning that the last element added will have the highest z-order. 31 | *** 32 | ### AddElement(ElementDescriptor) 33 | The AddElement method takes a single argument; an ElementDescriptor. ElementDescriptor is a UDT that defines exactly how the element will be drawn and how it reacts to events like mouse clicks. 34 | 35 | Public Type ElementDescriptor 36 | OnClick As LongPtr ' event function callback pointer 37 | OnDblClick As LongPtr ' event function callback pointer 38 | OnMouseDown As LongPtr ' event function callback pointer 39 | OnMouseUp As LongPtr ' event function callback pointer 40 | OnMouseEnter As LongPtr ' event function callback pointer 41 | OnMouseLeave As LongPtr ' event function callback pointer 42 | OnMouseMove As LongPtr ' event function callback pointer 43 | OnScrollH As LongPtr ' event function callback pointer 44 | OnScrollV As LongPtr ' event function callback pointer 45 | Left As Long ' pixel offset (control relative, DPI scaled) 46 | Top As Long ' pixel offset (control relative, DPI scaled) 47 | Width As Long ' pixel width (DPI scaled) 48 | Height As Long ' pixel width (DPI scaled) 49 | Cursor As MousePointerConstants ' cursor/pointer icon 50 | TrackingIdX As LongLong ' for tracking this element, passed to events 51 | TrackingIdY As LongLong ' for tracking this element, passed to events 52 | Text As String ' the text to render 53 | TextRenderingOptions As TextRendering ' options to customize text rendering (object) 54 | BackgroundFill As Fill ' options to customize back fill rendering (object) 55 | Corners As Corners ' options to customize corner rendering (object) 56 | Borders As Borders ' options to customize border rendering (object) 57 | End Type 58 | *** 59 | ### Tips 60 | - Each time your OnPaint method is called, you start with a blank canvas. 61 | 62 | - Left/Top/Width/Height can legitimately be outside of the canvas area. For example, negative Left/Top, or a Width/Height past the Canvas.Width/Canvas.Height has no ill-effects. The form engine will clip everything appropriately for you, allowing for much simpler designing of your control. 63 | 64 | - You should put thought into making the Paint routine efficient. Try not to instantiate COM objects, and when drawing multiple similar elements, try to re-use ElementDescriptors by setting up common properties outside of loops (see WaynesGrid for examples of this) 65 | 66 | - TrackingIdX and TrackingIdY are important when you have multiple elements within a control. The two values, when combined, should uniquely represent the element, and must be maintained if your Paint routine is called again. This is needed for supporting events. For example, in a grid control, each cell would have a TrackingIdX / TrackingIdY value associated with it, given the X/Y co-ordinates of the cell. 67 | 68 | - Currently, only mouse events are provided, but focus events are coming soon, as well as keyboard events. 69 | 70 | - You can use class-based event handlers by simply using the `AddressOf MyEvent` which is now possible to use even on class members. You can see this used frequently in the samples, such as WaynesGrid. All mouse events have the following format: 71 | ``` 72 | Class MyCustomControl 73 | ... 74 | Private Sub MyClickEvent(ByRef EventInfo As MouseEvent) 75 | MsgBox "You clicked me!" 76 | End Sub 77 | 78 | Private Sub OnPaint(ByVal Canvas As CustomControls.Canvas) _ 79 | Implements ICustomControl.Paint 80 | Dim MyDescriptor As ElementDescriptor 81 | MyDescriptor.OnClick = AddressOf MyClickEvent 82 | End Sub 83 | ``` 84 | EventInfo (MouseEvent) provides mouse information such as the relative X/Y position of the mouse, plus the TrackingX/Y values discussed earlier. 85 | 86 | - When you call Canvas.AddElement, your element goes into a render pipeline. It is **not** immediately painted to the screen. The render pipeline is compared to the previous render pipeline that was provided by you in the last OnPaint call, and the tB form engine will only redraw areas of the control that have changed. This allows for efficient painting of controls whilst not needing to be concerned about the finer details of how to do partial repainting. -------------------------------------------------------------------------------- /docs/_samples/customcontrols/propertysheetandserialization.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Property Sheets and Serialization 3 | category: customcontrols 4 | order: 5 5 | --- 6 | 7 | # Property Sheet & Object Serialization 8 | The form designer property sheet will pickup any **_public_** custom properties (fields) that you expose via your CustomControl class. For example, adding a field `Public MyField As Long` will then automatically show up in the control property sheet in the form designer: 9 | 10 | ![CustomControl MyField propertySheet](https://www.twinbasic.com/images/wiki/ccMyFieldPropertySheet1a.png) 11 | 12 | This is then persisted to your project as properties inside your form JSON structure: 13 | 14 | ![CustomControl MyField JSON](https://www.twinbasic.com/images/wiki/ccMyFieldJson1a.png) 15 | 16 | The key to making this work is your serialization constructor, which might look something like this: 17 | 18 | Public Sub New(Serializer As SerializationInfo) 19 | If Not Serializer.Deserialize(Me) Then 20 | InitializeDefaultValues ' you implement this 21 | End If 22 | End Sub 23 | If `Deserialize(Me)` returns `True`, then your class properties were synchronized with the properties set via the form designer. If it returns `False` then the control has just been added to the form, and this gives you an opportunity to setup any suitable default values for your custom public properties. The form designer notices default values you set within the serialization constructor, so that your property sheet is kept in-sync. 24 | *** 25 | ### Default Values 26 | An alternative method for setting up default values is to inline them into the class field definition: 27 | 28 | ![CustomControl MyField = 42](https://www.twinbasic.com/images/wiki/ccMyFieldPropertySheet1b.png) 29 | 30 | The `Deserialize(Me)` call inside your serialization constructor will overwrite the property value if the control is being synchronized from the persisted property sheet data. 31 | *** 32 | ### Enumerations 33 | Enumerations that you define in your twinBASIC project are supported. Simply expose a class field with the enumeration: 34 | 35 | ![CustomControl enumeration property sheet example](https://www.twinbasic.com/images/wiki/ccMyEnumFieldPropertySheet.png) 36 | 37 | Note: Enumerations are persisted to the form JSON structure as strings, so bare this in mind when making changes/updates to a CustomControl so that you don't introduce breaking changes by renaming an enumeration value. 38 | *** 39 | ### Objects 40 | Class objects that you define in your twinBASIC project are supported. You ***must*** supply a ClassId attribute for any exposed object, so that the serialization can identify it. 41 | 42 | ![CustomControl class property sheet example](https://www.twinbasic.com/images/wiki/ccMyFieldClass.png) 43 | *** 44 | ### Arrays 45 | Arrays are supported. The form designer allows for adding new elements, removing elements, and re-ordering of elements (via drag/drop). 46 | 47 | ![CustomControl array property sheet example](https://www.twinbasic.com/images/wiki/ccMyFieldArray.png) 48 | *** 49 | ### Property Get / Let 50 | Custom property procedures are supported. You will find that using Property Get / Let procedures is required if you want property changes to trigger repainting of your control. 51 | 52 | ![CustomControl custom property example](https://www.twinbasic.com/images/wiki/ccMyFieldCustomProperty.png) 53 | 54 | Note that _**private**_ fields and properties do not form part of the serialization, and so will not appear on the property sheet. 55 | *** 56 | ### Avoid Variants 57 | The serialization does not support Variants or generic Objects. Always use strongly-typed datatypes. 58 | *** 59 | ### Events 60 | Events that you define in your class will be exposed in the Events property sheet: 61 | 62 | ![CustomControl attribute](https://www.twinbasic.com/images/wiki/ccEvents.png) 63 | 64 | At the moment, the form-designer doesn't yet support code-behind-forms, so this feature is not yet complete. 65 | *** 66 | ### Tips 67 | - If you make changes to your CustomControl class, such as exposing new properties or changing how a control is drawn, these changes will get reflected immediately to any open form designers. Form designers will show a 'resync' button when you return to them, once pressed the changes will be apparent. 68 | 69 | - The serialization happens via JSON when running in the IDE, but via a binary format when running in a compiled DLL/EXE. The `SerializationInfo` object that is passed to your serialization constructor is a different implementation when running in the IDE, but this should be transparent to you as a CustomControl implementer. 70 | 71 | - When making changes or updates to a CustomControl always consider backwards compatibility. For example, if you rename an exposed property, the old property values stored via the property sheet won't be deserialized to your new property. -------------------------------------------------------------------------------- /docs/_samples/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /samples/index.html 3 | --- 4 | This is tB samples main page. 5 | 6 |

Table of Contents

7 | 8 | {% assign mydocs = site.samples | group_by: 'category' %} 9 | {% for cat in mydocs %} 10 | {% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} 11 | {% if catdata %} 12 |

{{ catdata.title }}

13 |

{{ catdata.description }}

14 | {% else %} 15 |

{{ cat.name }}

16 | {% endif %} 17 | 23 | {% endfor %} -------------------------------------------------------------------------------- /docs/_samples/packages/createpackage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating a TWINPACK package 3 | category: packages 4 | order: 1 5 | --- 6 | 7 | ### Creating a TWINPACK package 8 | 9 | To create a new TWINPACK package, navigate to the twinBASIC activity panel and choose the option labelled 'Package': 10 | 11 | Create Package 12 |
13 |
14 | 15 | Once you've created the project, you should find the extra 'TWINBASIC PACKAGE MANAGER' panel in the main Explorer activity panel: 16 | 17 | Create Package 18 |
19 |
20 | 21 | You should now edit the Namespace, Description, Licence and Visibility properties appropriately by using the package manager 'EDIT' links, which will take you to the individual settings in the `Settings` file. Once you've edited them, remember to close (and save) the `Settings` file in order for your changes to be reflected in the package manager panel. 22 | 23 | - **Namespace:** this is the symbol that will be used to group your components in projects that reference your package. For example, a package that provides a series of different dialog classes might use the namespace `Dialogs`. 24 | - **Description:** this is the descriptive text that will appear in the `Settings`->`References` list. If you plan to share this package, it is wise to think carefully about the description so that others can find your package easily through TWINSERV. 25 | - **Licence:** this short text appears in the `Settings`->`References` list, alongside the Description. If you plan to share this package, it is important that you enter this field, and the value you enter here should appropriately match the content of the LICENCE.md file (e.g. 'MIT', 'LGPL' etc). 26 | - **Visibility:** determines whether the package is visible to only you (PRIVATE) or everyone (PUBLIC). The value set here only takes effect when you use the 'PUBLISH THIS PACKAGE' button to publish your package in the package manager service, TWINSERV. 27 | 28 | *If you don't plan to publish your package on TWINSERV, then you don't need to fill in the **Licence** or **Visibility** fields.* 29 | 30 | You can now create components (Class, Module, Interface) in your project as normal, and when you are finished, it's time to finalize the package. You have two options; 31 | 32 |
33 | 34 | ### OPTION 1 - Finalize the package into a TWINPACK file 35 | 36 | Use this option if you want to just create a local TWINPACK file that you can use in other projects. For this, the build process is the same as any ordinary twinBASIC build... just hit the Build button in the TWINBASIC panel: 37 | 38 | Create Package 39 |
40 |
41 | 42 | You'll see the build output notification in the `DEBUG CONSOLE`, as seen above. 43 | 44 | Job done. See [Importing a package from a TWINPACK file](https://github.com/WaynePhillipsEA/twinbasic/wiki/twinBASIC-Packages-Importing-a-package-from-a-TWINPACK-file) for referencing and using the TWINPACK file in other twinBASIC projects. 45 | 46 |
47 | 48 | ### OPTION 2 - Publish the package directly to the package manager service (TWINSERV) 49 | 50 | If you're publishing your package onto TWINSERV, you don't need to create the TWINPACK file manually. Just use the 'PUBLISH THIS PACKAGE' button: 51 | 52 | Create Package 53 |
54 |
55 | 56 | ***Publishing packages onto TWINSERV requires you to first create a publisher account. If you haven't done so, you'll be prompted to do so at this stage.*** 57 | 58 | You will then be prompted to confirm the package details: 59 | 60 | Create Package 61 |
62 |
63 | 64 | After pressing `YES`, the package will be uploaded to TWINSERV. Check the `DEBUG CONSOLE` for completion notices: 65 | 66 | Create Package 67 |
68 |
69 | 70 | If the package got uploaded successfully, it should be available via TWINSERV within a few moments. If you've created a `PUBLIC` package, others will be able to see and download it at this point. 71 | 72 | See [Importing a package from TWINSERV](https://github.com/WaynePhillipsEA/twinbasic/wiki/twinBASIC-Packages-Importing-a-package-from-TWINSERV) for referencing and using the uploaded packages. 73 | 74 |
75 |
76 | 77 | ### Special files LICENCE.md and CHANGELOG.md 78 | 79 | When you create a new package project, you'll see two additional files created for you in the project filesystem: 80 | 81 | Create Package 82 |
83 |
84 | 85 | If you're publishing a `PUBLIC` package to the package manager service, it is important that you edit these two files before publishing. These are both markdown files, and will in future become more accessible to users that are considering using your package from TWINSERV. -------------------------------------------------------------------------------- /docs/_samples/packages/importpackagefromfile.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Importing a package from a TWINPACK file 3 | category: packages 4 | order: 3 5 | --- 6 | 7 | ### Importing a package from a TWINPACK file 8 | 9 | To import a package directly from a TWINPACK file (instead of using TWINSERV), follow these steps. 10 | 11 | - open the project from which you want to use a package 12 | - open the `Settings` file within it 13 | - navigate to the References section 14 | - select the 'TWINPACK PACKAGES' button 15 | - press the 'Import from file...' button: 16 | Create Package 17 |
18 |
19 | 20 | - choose the TWINPACK file you want to import, and then it should appear in the references list (ticked): 21 | Create Package 22 |
23 |
24 | 25 | - close and save the `Settings` file to restart the compiler 26 | 27 | Now you're ready to use the package! In the example shown above I added a reference to the TwinLib64 package, and I can now confirm that I can access components from the TwinLib64 package in my code: 28 | 29 | Create Package 30 |
31 |
-------------------------------------------------------------------------------- /docs/_samples/packages/importpackagefromtwinserv.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Import a package from TWINSERV 3 | category: packages 4 | order: 4 5 | --- 6 | 7 | ### Importing a package from TWINSERV 8 | 9 | Open the project from which you want to use a package, open the `Settings` file within it and navigate to the References section. Select the 'TWINPACK PACKAGES' button, and all packages that are on the server should be shown: 10 | 11 | Create Package 12 |
13 |
14 | 15 | If you tick one of the available packages, it will be downloaded and imported into the project: 16 | 17 | Create Package 18 |
19 |
20 | 21 | Once you're finished, save and close the Settings file which will cause the compiler to be restarted. Now you're ready to use the package! In the example shown above I added a reference to the TwinLib64 package, and I can now confirm that I can access components from the TwinLib64 package in my code: 22 | 23 | Create Package 24 |
25 |
26 | 27 | Note: I have a couple of PRIVATE packages that I have published, which are only available to me when I am signed in. If you are not already signed in, you will see a warning link that you can click to login: 28 | 29 | Create Package 30 |
31 |
32 | 33 | After logging in, press the 'TWINPACK PACKAGES' button again to refresh the list. -------------------------------------------------------------------------------- /docs/_samples/packages/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: What's a package? 3 | category: packages 4 | order: 1 5 | --- 6 | 7 | ### What's a package? 8 | 9 | In twinBASIC, a *package* is a collection of components that you can reference from another twinBASIC project. The components can be modules, classes or interfaces. 10 | 11 | A twinBASIC package is distributed as a TWINPACK file that contains everything needed by the components in that package. A project that references a TWINPACK package, imports the whole package into the file system of the root project, resulting in no external dependencies. 12 | 13 | With TWINPACK packages you group common components together into their own namespace whilst allowing for convenient code reuse without any of the problems often associated with using external DLL libraries. 14 | 15 | twinBASIC comes complete with a package manager service called TWINSERV, allowing you to easily share and distribute TWINPACK packages to other twinBASIC developers. 16 | 17 | Please be aware that TWINPACK files currently contain the full sourcecode of your packaged components. It is planned that we will in future allow for creating binary (compiled) TWINPACK files for developers that hold an Ultimate edition licence of twinBASIC. -------------------------------------------------------------------------------- /docs/_samples/packages/updatepackage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Updating a package 3 | category: packages 4 | order: 5 5 | --- 6 | 7 | ### Updating a package 8 | 9 | #### NOTE: at the moment, the twinBASIC VS Code extension does not notify you about package updates that are available on TWINSERV. This feature is planned, and will be available soon. 10 | 11 | If you find an updated package is available on TWINSERV, you must first remove the old package from your project by deselecting it: 12 | 13 | Deselect a Package 14 |
15 |
16 |
17 | 18 | You will then be prompted to remove it from the filesystem: 19 | 20 | Deselect a Package 21 |
22 |
23 |
24 | 25 | Select YES. Now, you can add the updated package to your project as usual. See [Importing a package from TWINSERV](https://github.com/WaynePhillipsEA/twinbasic/wiki/twinBASIC-Packages-Importing-a-package-from-TWINSERV). 26 | 27 | #### Don't forget to close the Settings file and save the changes! (which will in turn cause a restart of the compiler). 28 | -------------------------------------------------------------------------------- /docs/_samples/webview2/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting started 3 | category: webview2 4 | order: 1 5 | --- 6 | 7 | ### Getting Started 8 | 9 | #### Package requirements 10 | 11 | To create projects that use WebView2, your projects must include both the `WinNativeForms` package and the `WebView2` package in your projects. 12 | 13 | Both of these packages can be added through the `Project` > `References` menu option, and selecting the `TWINPACK PACKAGES` button. Ensure both packages are ticked, and then close and save the Settings file and restart the compiler. 14 | 15 | Create Package 16 |
17 |
18 | 19 | Once you've added the package references, you should find that the WebView2 control is now available to you in the form designer: 20 | 21 | Create Package 22 |
23 |
24 | 25 | #### Create a WebView2 control on a form 26 | 27 | We use the WebView2 control just like any ordinary control: 28 | 29 | Create Package 30 |
31 |
32 | 33 | #### WebView2 control properties 34 | 35 | There are lots of WebView2 properties and events to experiment with. 36 | 37 | Create Package 38 |
39 |
40 | Note that toggling any property will show extra information at the bottom of the properties list to give you a little bit more information. For further information on a particular property, try searching the official WebView2 documentation 41 | 42 | ## Samples 43 | 44 | If you prefer to start with a sample, have a look at `Sample 0. WebView2 Examples`, available in the new-project dialog: 45 | 46 | Create Package 47 | -------------------------------------------------------------------------------- /docs/_samples/webview2/reentrancy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Information about re-entrancy 3 | category: webview2 4 | order: 3 5 | --- 6 | 7 | ## Information about re-entrancy 8 | 9 | The WebView2 API is very particular about not allowing for re-entrancy from its events (see Threading model for WebView2 apps). This means that when we process events such as `NavigationCompleted` we are ordinarily prohibited from doing anything with the WebView2 object model before returning from that event. So for example, you couldn't navigate to a new URL from within the `NavigivationCompleted` event itself. 10 | 11 | To work around these limitations, our WebView2 implementation defers all event handling by retriggering events through the form message loop. This allows events to be handled and execution control returns to WebView2 immediately, and then our deferred event gets triggered once WebView2 returns to the main message loop. 12 | 13 | Due to the design of our implementation, for the most part you can forget about the re-entrancy limitations imposed by the WebView2 API. However, if you use the `AddObject` feature of WebView2 which allows you to expose a twinBASIC class instance to javascript, then you need to be aware that there are two modes available for the `AddObject` feature. 14 | 15 | #### AddObject(ObjectInstance As Object, UseDeferredInvoke As Boolean) 16 | 17 | If you pass `True` to the `UseDeferredInvoke` parameter of the `AddObject` call, then calls that come in to your class instance from javascript will be treated **asynchronously** and so you cannot return a value to javascript. This is great for event notifications. 18 | 19 | If you pass `False` to the `UseDeferredInvoke` parameter of the `AddObject` call, then calls that come in to your class instance from javascript will be treated **synchronously** and so you can return a value to be consumed by javascript, but you MUST ensure that you don't cause re-entrancy, so you MUST NOT make calls back into the WebView2 control methods and properties. Be warned: if you do make calls back into the WebView2 control when you're not using `UseDeferredInvoke`, then you will cause deadlocks leading to your application becoming unstable and sometimes lingering in the task manager after shutdown. 20 | 21 | Note that it is perfectly acceptable to add two separate objects, one for asynchronous event handling (using `UseDeferredInvoke:=True`) and another for synchronous properties (using `UseDeferredInvoke:=False`). -------------------------------------------------------------------------------- /docs/_samples/webview2/userdatafolder.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Customize the UserDataFolder 3 | category: webview2 4 | order: 2 5 | --- 6 | 7 | ## Customize the UserDataFolder 8 | 9 | At runtime, WebView2 needs a working folder for storing data used during the session.  By default, a folder will be created in the same folder as your executable file, called `.WebView2` (e.g. `MyApp.Exe.WebView2`).  If this folder cannot be created, the WebView2 control will not work (you can catch the controls Error event to determine this at runtime). 10 | 11 | This default behaviour is not always appropriate.  For example, if you're creating an Addin for Microsoft Access, then you almost certainly will not be allowed to create a folder called `MSACCESS.EXE.WebView2` in the Office sub folder of your systems Program Files folder. 12 | 13 | It is HIGHLY recommended that you override the default behaviour, and instead provide a path that is considered to be safe to use for storing such data. To override the UserDataFolder path at runtime, handle the Create event of the WebView2 control.  See the example in `Sample 9. ActiveX Control WebView2 + Monaco` here, where we use the `%APPDATA%\Local` system path: 14 | 15 | Create Package 16 |
17 |
18 | 19 | Set the `EnvironmentOptions.UserDataFolder` property to a string containing the output path to use (folder will be created if necessary). -------------------------------------------------------------------------------- /docs/assets/lazysizes.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e){var t=function(u,D,f){"use strict";var k,H;if(function(){var e;var t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:true,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:true,ricTimeout:0,throttleDelay:125};H=u.lazySizesConfig||u.lazysizesConfig||{};for(e in t){if(!(e in H)){H[e]=t[e]}}}(),!D||!D.getElementsByClassName){return{init:function(){},cfg:H,noSupport:true}}var O=D.documentElement,i=u.HTMLPictureElement,P="addEventListener",$="getAttribute",q=u[P].bind(u),I=u.setTimeout,U=u.requestAnimationFrame||I,o=u.requestIdleCallback,j=/^picture$/i,r=["load","error","lazyincluded","_lazyloaded"],a={},G=Array.prototype.forEach,J=function(e,t){if(!a[t]){a[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")}return a[t].test(e[$]("class")||"")&&a[t]},K=function(e,t){if(!J(e,t)){e.setAttribute("class",(e[$]("class")||"").trim()+" "+t)}},Q=function(e,t){var a;if(a=J(e,t)){e.setAttribute("class",(e[$]("class")||"").replace(a," "))}},V=function(t,a,e){var i=e?P:"removeEventListener";if(e){V(t,a)}r.forEach(function(e){t[i](e,a)})},X=function(e,t,a,i,r){var n=D.createEvent("Event");if(!a){a={}}a.instance=k;n.initEvent(t,!i,!r);n.detail=a;e.dispatchEvent(n);return n},Y=function(e,t){var a;if(!i&&(a=u.picturefill||H.pf)){if(t&&t.src&&!e[$]("srcset")){e.setAttribute("srcset",t.src)}a({reevaluate:true,elements:[e]})}else if(t&&t.src){e.src=t.src}},Z=function(e,t){return(getComputedStyle(e,null)||{})[t]},s=function(e,t,a){a=a||e.offsetWidth;while(a49?function(){o(t,{timeout:n});if(n!==H.ricTimeout){n=H.ricTimeout}}:te(function(){I(t)},true);return function(e){var t;if(e=e===true){n=33}if(a){return}a=true;t=r-(f.now()-i);if(t<0){t=0}if(e||t<9){s()}else{I(s,t)}}},ie=function(e){var t,a;var i=99;var r=function(){t=null;e()};var n=function(){var e=f.now()-a;if(e0;if(r&&Z(i,"overflow")!="visible"){a=i.getBoundingClientRect();r=C>a.left&&pa.top-1&&g500&&O.clientWidth>500?500:370:H.expand;k._defEx=u;f=u*H.expFactor;c=H.hFac;A=null;if(w2&&h>2&&!D.hidden){w=f;N=0}else if(h>1&&N>1&&M<6){w=u}else{w=_}}if(l!==n){y=innerWidth+n*c;z=innerHeight+n;s=n*-1;l=n}a=d[t].getBoundingClientRect();if((b=a.bottom)>=s&&(g=a.top)<=z&&(C=a.right)>=s*c&&(p=a.left)<=y&&(b||C||p||g)&&(H.loadHidden||x(d[t]))&&(m&&M<3&&!o&&(h<3||N<4)||W(d[t],n))){R(d[t]);r=true;if(M>9){break}}else if(!r&&m&&!i&&M<4&&N<4&&h>2&&(v[0]||H.preloadAfterLoad)&&(v[0]||!o&&(b||C||p||g||d[t][$](H.sizesAttr)!="auto"))){i=v[0]||d[t]}}if(i&&!r){R(i)}}};var a=ae(t);var S=function(e){var t=e.target;if(t._lazyCache){delete t._lazyCache;return}L(e);K(t,H.loadedClass);Q(t,H.loadingClass);V(t,B);X(t,"lazyloaded")};var i=te(S);var B=function(e){i({target:e.target})};var T=function(e,t){var a=e.getAttribute("data-load-mode")||H.iframeLoadMode;if(a==0){e.contentWindow.location.replace(t)}else if(a==1){e.src=t}};var F=function(e){var t;var a=e[$](H.srcsetAttr);if(t=H.customMedia[e[$]("data-media")||e[$]("media")]){e.setAttribute("media",t)}if(a){e.setAttribute("srcset",a)}};var s=te(function(t,e,a,i,r){var n,s,o,l,u,f;if(!(u=X(t,"lazybeforeunveil",e)).defaultPrevented){if(i){if(a){K(t,H.autosizesClass)}else{t.setAttribute("sizes",i)}}s=t[$](H.srcsetAttr);n=t[$](H.srcAttr);if(r){o=t.parentNode;l=o&&j.test(o.nodeName||"")}f=e.firesLoad||"src"in t&&(s||n||l);u={target:t};K(t,H.loadingClass);if(f){clearTimeout(c);c=I(L,2500);V(t,B,true)}if(l){G.call(o.getElementsByTagName("source"),F)}if(s){t.setAttribute("srcset",s)}else if(n&&!l){if(d.test(t.nodeName)){T(t,n)}else{t.src=n}}if(r&&(s||l)){Y(t,{src:n})}}if(t._lazyRace){delete t._lazyRace}Q(t,H.lazyClass);ee(function(){var e=t.complete&&t.naturalWidth>1;if(!f||e){if(e){K(t,H.fastLoadedClass)}S(u);t._lazyCache=true;I(function(){if("_lazyCache"in t){delete t._lazyCache}},9)}if(t.loading=="lazy"){M--}},true)});var R=function(e){if(e._lazyRace){return}var t;var a=n.test(e.nodeName);var i=a&&(e[$](H.sizesAttr)||e[$]("sizes"));var r=i=="auto";if((r||!m)&&a&&(e[$]("src")||e.srcset)&&!e.complete&&!J(e,H.errorClass)&&J(e,H.lazyClass)){return}t=X(e,"lazyunveilread").detail;if(r){re.updateElem(e,true,e.offsetWidth)}e._lazyRace=true;M++;s(e,t,r,i,a)};var r=ie(function(){H.loadMode=3;a()});var o=function(){if(H.loadMode==3){H.loadMode=2}r()};var l=function(){if(m){return}if(f.now()-e<999){I(l,999);return}m=true;H.loadMode=3;a();q("scroll",o,true)};return{_:function(){e=f.now();k.elements=D.getElementsByClassName(H.lazyClass);v=D.getElementsByClassName(H.lazyClass+" "+H.preloadClass);q("scroll",a,true);q("resize",a,true);q("pageshow",function(e){if(e.persisted){var t=D.querySelectorAll("."+H.loadingClass);if(t.length&&t.forEach){U(function(){t.forEach(function(e){if(e.complete){R(e)}})})}}});if(u.MutationObserver){new MutationObserver(a).observe(O,{childList:true,subtree:true,attributes:true})}else{O[P]("DOMNodeInserted",a,true);O[P]("DOMAttrModified",a,true);setInterval(a,999)}q("hashchange",a,true);["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){D[P](e,a,true)});if(/d$|^c/.test(D.readyState)){l()}else{q("load",l);D[P]("DOMContentLoaded",a);I(l,2e4)}if(k.elements.length){t();ee._lsFlush()}else{a()}},checkElems:a,unveil:R,_aLSL:o}}(),re=function(){var a;var n=te(function(e,t,a,i){var r,n,s;e._lazysizesWidth=i;i+="px";e.setAttribute("sizes",i);if(j.test(t.nodeName||"")){r=t.getElementsByTagName("source");for(n=0,s=r.length;n summary::before{ 78 | content : '−'; 79 | } -------------------------------------------------------------------------------- /docs/images/twinBASICIconTransparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twinbasic/documentation/a9edde28713c6bbed2ff2032f8eaf1b522e60e0a/docs/images/twinBASICIconTransparent.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Work in progress... 2 | Check back soon. The site is under active construction, please don't enter without a hard hat. 3 | 4 |

Table of Contents

5 | 6 | {% assign mydocs = site.samples | group_by: 'category' %} 7 | {% for cat in mydocs %} 8 | {% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} 9 | {% if catdata %} 10 |

{{ catdata.title }}

11 |

{{ catdata.description }}

12 | {% else %} 13 |

{{ cat.name }}

14 | {% endif %} 15 |
    16 | {% assign items = cat.items | sort: 'order' %} 17 | {% for item in items %} 18 |
  • {{ item.title }}
  • 19 | {% endfor %} 20 |
21 | {% endfor %} 22 | 23 |
    24 | {% assign mydocs = site.samples | group_by: 'category' %} 25 | {% for cat in mydocs %} 26 |
  • 27 | {% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} 28 |
    29 | {% if catdata %} 30 | {{ catdata.title }} 31 |

    {{ catdata.description }}

    32 |
    33 | {% else %} 34 | {{ cat.name }} 35 | {% endif %} 36 | {% assign items = cat.items | sort: 'order' %} 37 |
      38 | {% for item in items %} 39 |
    • 40 |
      41 | {{ item.title }} 42 |
      43 |
    • 44 | {% endfor %} 45 |
    46 |
    47 |
  • 48 | {% endfor %} 49 |
-------------------------------------------------------------------------------- /docs/samples.md: -------------------------------------------------------------------------------- 1 | This is tB samples main page. 2 | 3 |

Table of Contents

4 | 5 | {% assign mydocs = site.samples | group_by: 'category' %} 6 | {% for cat in mydocs %} 7 | {% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} 8 | {% if catdata %} 9 |

{{ catdata.title }}

10 |

{{ catdata.description }}

11 | {% else %} 12 |

{{ cat.name }}

13 | {% endif %} 14 |
    15 | {% assign items = cat.items | sort: 'order' %} 16 | {% for item in items %} 17 |
  • {{ item.title }}
  • 18 | {% endfor %} 19 |
20 | {% endfor %} -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: 3 | --- 4 | 5 | 6 | 7 | {% for page in site.pages %} 8 | {% if page.url contains '.xml' or page.url contains 'assets' %}{% else %} 9 | 10 | {{ site.url }}{{ page.url }} 11 | monthly 12 | 1.0 13 | 14 | {% endif %} 15 | {% endfor %} 16 | {% for page in site.posts %} 17 | 18 | {{ site.url }}{{ page.url | replace: 'index.html', '' }} 19 | monthly 20 | 1.0 21 | 22 | {% endfor %} 23 | {% for page in site.without-plugin %} 24 | 25 | {{ site.url }}{{ page.url | replace: 'index.html', '' }} 26 | monthly 27 | 1.0 28 | 29 | {% endfor %} 30 | --------------------------------------------------------------------------------