VDSTools

Chrome de fenêtre, barre d'outils et contrôles macOS natifs, en Xojo pur — aucun plugin, aucun Objective-C compilé. Cible : macOS 15 et au-delà.

101classes
774méthodes publiques
8sous-dossiers
15+macOS

Le modèle

Trois idées portent toute la bibliothèque. Les comprendre dispense de lire le reste dans l'ordre.

Le registre de propriétaires

Un rappel du runtime Objective-C ne reçoit qu'un pointeur nu. Cocoa.RegisterOwner associe ce pointeur à l'objet Xojo, dans un dictionnaire de WeakRef qui se purge à la lecture. OwnerOf le retrouve.

Une cible, pas cinq sous-classes

Un seul objet créé au runtime porte itemAction: et validateToolbarItem:. AppKit interroge la cible avant de valider un item : clics et grisage marchent sans une ligne de code compilé.

Héberger dedans, pas à côté

Une vue AppKit entre dans la vue d'un DesktopCanvas servant d'ancre. Xojo continue de placer l'ancre, l'autoresizing fait suivre : aucune géométrie à recalculer.

Compatibilité

La cible est macOS 15, mais plusieurs réglages sont apparus plus tard — ou plus tôt et ne valent que la peine d'être notés. Chacun est protégé par Cocoa.Responds ou par un ClassRef nul : sur un système antérieur, l'appel est sans effet, jamais une erreur.

DepuisCe qui en dépend
macOS 10.10NativeStatusItem — tout passe par button, les accesseurs de l'item sont dépréciés
macOS 10.13NativeLevelIndicator.SetBands (fillColor), NativeSegmentedControl.SetDistribution
macOS 10.15NativeSwitch, NativeColorSampler
macOS 11NativeFilePanel.SetAllowedExtensions (UTType), NativeButton.SetDestructive, NativeAlert.SetDestructiveButton, titre et sous-titre de fenêtre, styles de barre d'outils
macOS 13NativeComboButton, NativeColorWell.Styles.Minimal et .Expanded
macOS 14NativeButton.BezelStyles.Automatic, NativePopover.SetFullSizeContent, presque tout NativeMenu — en-têtes de section, pastilles, palettes, modes de sélection ; les sous-titres attendent 14.4
macOS 26NativeGlassEffectView, NativeButton.BezelStyles.Glass, badge et teinte de fond des items de barre d'outils
macOS 27NativeMenu.ImageVisibility — sans lui, les symboles des items disparaissent —, NativeGlassEffectView.Interactive

Pièges

Ceux qui ont coûté cher. Presque tous ont un symptôme qui pointe ailleurs que la cause.

Xojo efface l'image d'un bouton hérité, indéfiniment

Mesuré le 17 septembre 2026 sur un DesktopButton posé dans une fenêtre. setImage: est bien reçu — juste après l'appel, [button image] rend l'image et imagePosition la valeur posée. Au clic SUIVANT, avant d'y toucher : image absente, imagePosition retombé à 0. Personne n'y avait touché entre-temps.

Ni la cellule ni le bezel ne sont en cause : cellule NSButtonCell ordinaire, bezel Push, qui dessinent parfaitement une icône hors de Xojo. XOJButton ne redéfinit aucune méthode de dessin — seulement des événements. Mais le framework appelle lui-même setImage:, setImagePosition: et setButtonType:, ce dernier remettant image et bezel, et il le fait APRÈS Opening puis à chaque passage.

Ce qui ne marche pas : Timer.CallLater(0) pour poser l'image plus tard, setNeedsDisplay: pour forcer le dessin. Il n'existe aucun point d'accroche avant le dessin d'un contrôle hérité.

Ce qui marche : HÉBERGER plutôt qu'hériter — NativeIconButtonControl. Le bouton est alors créé par la bibliothèque, Xojo ne le connaît pas et ne le reconfigure jamais.

Une icône au-dessus du titre sort du cadre, avec le bezel Push

Relevé au rendu, sur macOS 27. Avec ImagePosition = Above (ou Below) et le bezel Push, celui du bouton ordinaire, AppKit dessine l'icône dans le cadre et le titre DEHORS, sous la pastille. Essayé à 32, 40, 46, 52 et 60 points de haut : le cadre garde sa hauteur fixe et le texte reste à l'extérieur, à toutes les hauteurs.

La cause n'est pas la place manquante : le bezel Push a une hauteur propre, que le cadre du contrôle ne commande pas. fittingSize ne prévient de rien — il rend 24 points de haut pour Above comme pour un bouton sans image.

Ce qui marche : un bezel qui accepte de grandir — FlexiblePush (2) ou SmallSquare (10), vérifiés tous les deux. L'icône et le titre tiennent alors dans le cadre, empilés. Avec Leading, Trailing, Left ou Right, le bezel Push convient parfaitement.

La ligne qu'on glisse disparaît : l'image d'AppKit ne suffit pas

Relevé image par image sous macOS 27, sur deux enregistrements. L'image : pour une table à base de vues, l'en-tête dit qu'AppKit la compose des draggingImageComponents de NSTableCellView — son champ de texte et son image. Des cellules NSView ordinaires n'en fournissent presque rien : un titre blanc, puis plus rien. La sélection : en style Gap, la ligne saisie est masquée pendant tout le glisser ; ce qu'on déplace n'est plus visible nulle part. Et au milieu d'une ligne, AppKit propose DropOn ; le refuser laisse sans destination.

Ce qui marche, et reproduit Numbers : style Regular, pour que la ligne d'origine reste en place ; photographier les lignes dès pasteboardWriterForRow: par cacheDisplayInRect: sur la table ; poser dans la table une vue d'ombre — ces photos empilées dans une carte opaque à coins arrondis et liseré couleur d'accent, l'ombre portée par une vue extérieure qui ne coupe rien (une simple copie translucide se confondait avec le fond blanc de macOS 27) — que validateDrop: déplace à chaque mouvement d'après draggingLocation, et que draggingSession:endedAtPoint: retire ; vider l'image d'AppKit par setDraggingFrame:contents: ; recadrer DropOn en DropAbove par setDropRow:dropOperation:.

Sous macOS 27, un champ blanc sur une fenêtre blanche

Le champ n'a pas perdu sa bordure : il a perdu son contraste. Relevé sur un système 27.0 en apparence claire, windowBackgroundColor vaut désormais 255/255/255 — exactement le blanc de textBackgroundColor, l'intérieur du champ. Il ne reste qu'un filet d'environ 12 % de gris, que l'œil ne voit plus sur une capture réduite. Square et Rounded se dessinent alors à l'identique, et tous les champs sont concernés : DesktopTextField comme NativeTextField, c'est le même NSTextField.

Deux remèdes intuitifs ne marchent pas, mesurés eux aussi : poser un backgroundColor sur un champ à bezel est ignoré, et retirer le bezel pour un simple filet donne un trait dur, blanc vif en sombre. Ce qui marche est la mise en page des Réglages : poser les champs dans un cadre de groupe, dont le gris fait ressortir le blanc — et un NSBox se dessine aussi sous macOS 15, sans test de version. Attention au titre vide : il réserve quand même 12 points en haut du cadre. Augmenter le contraste, dans les réglages d'accessibilité, renforce les bordures ; c'est le choix de l'utilisateur, pas de l'application.

Sous macOS 27, les icônes des menus disparaissent sans erreur

Le code n'a pas changé, le symbole est bien posé par setImage:, et le menu s'ouvre sans icône. L'en-tête de NSMenuItem le dit en toutes lettres : à partir de macOS 27, AppKit « determines the visibility of menu item images, and will typically hide images ». La nouvelle propriété preferredImageVisibility vaut Automatic à la création — relevé sur un système 27.0.

Le remède tient en un réglage, Visible, derrière un test de sélecteur. NativeMenu le pose par défaut : un symbole passé en argument est une demande explicite, et le rendre au système reste possible par ImageVisibility = Automatic. Le piège ne concerne que les items à image : les pastilles d'un menu palette n'en ont pas.

Tester une méthode de CLASSE : deux idiomes, deux arguments différents

respondsToSelector: est un MESSAGE envoyé à un objet : il cherche dans la classe de cet objet. Pour une méthode de classe, on l'envoie donc à la classe elle-même. L'envoyer à la métaclasse fait chercher dans la méta-métaclasse, et ne trouve jamais rien.

La fonction du runtime class_respondsToSelector(cls, sel) est l'autre idiome : elle regarde les méthodes d'instance de la classe qu'on lui donne, si bien que pour une méthode de classe il faut lui passer la métaclasse. Les deux sont justes ; les mélanger ne l'est pas.

Le symptôme est muet et trompeur : une fonctionnalité se déclare indisponible sur une machine qui la prend en charge, sans erreur nulle part. Constaté sur les curseurs de macOS 15, rapportés absents sur un système 15.7.9.

Ne jamais déduire la géométrie d'un volet de celle d'un autre

Sous NSSplitViewController, deux volets pleine hauteur ont la même hauteur — en régime établi. AppKit ne les redimensionne pas au même instant, et une bascule en plein écran suffit à le montrer : placer le contenu de l'inspecteur d'après la hauteur que rapporte l'événement de redimensionnement du détail donne un cadre faux.

Le symptôme trompe deux fois. Trop haut à l'aller : l'origine d'AppKit étant EN BAS, le contenu sort par le haut du volet et le panneau paraît vide — ce qui se lit comme un défaut de dessin, pas comme un cadre trop grand. Trop court au retour : le contenu se retrouve collé en bas. Et rien n'apparaît en régime établi, seulement pendant la transition.

Chaque volet doit être lu par ses propres bounds. La valeur reçue dans l'événement ne sert que de repli pour la toute première passe, avant que le contrôleur n'ait posé le volet — à la construction, ses bounds valent encore ceux de sa fabrique.

La palette de personnalisation passe par le même delegate

toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: sert deux usages : peupler la barre, et construire la feuille de personnalisation. Rendre le même NSToolbarItem dans les deux cas confond l'item affiché dans la feuille et celui de la barre : le glisser vers la barre ne fait rien, sans la moindre erreur. L'en-tête l'énonce — each toolbar receives its own distinct copies and each time this method is called a new instance, et la palette est construite par cette même méthode.

NSToolbarItem étant NSCopying, on rend une copie autoreleasée quand willBeInserted vaut NO, et l'instance réelle quand il vaut YES : les changements de propriétés à chaud sur un item déjà posé continuent alors de fonctionner.

Deux ordres décident du reste. autosavesConfiguration doit valoir YES AVANT setToolbar: — c'est à cet instant qu'AppKit relit la configuration enregistrée ; posé après, il ne fait plus qu'écrire, et la barre revient au jeu par défaut à chaque ouverture. Et displayMode et le style doivent être posés avant l'attache, comme valeurs de départ : posés après, ils écrasent à chaque fois le mode que l'utilisateur vient de choisir dans la feuille.

La clé d'enregistrement est NSToolbar Configuration <identifiant> dans les préférences de l'application — relevée, pas devinée. Aucune API ne la remet à zéro : il faut la supprimer et réinsérer les identifiants du jeu par défaut.

NSOutlineView compare les pointeurs qu'on lui remet

La source de données rend un « item » par nœud, et NSOutlineView conserve ces objets et les compare pour savoir ce qui est déplié et ce qui est sélectionné. Rendre un nouvel objet à chaque appel — même équivalent — fait perdre le repli et la sélection à chaque rafraîchissement.

Il faut donc des clés stables et retenues : une NSString par nœud, liée à son numéro — jamais à sa ligne, qui change dès qu'on insère ou déplace —, mise en cache dans un Dictionary, avec la table inverse pour retrouver le nœud depuis le pointeur. Une clé reste retenue jusqu'au vidage de l'arbre, même pour un nœud retiré : AppKit peut encore la tenir pendant l'animation de suppression. Et setOutlineTableColumn: désigne la colonne qui porte les triangles : sans lui, AppKit les place où il veut et l'indentation ne suit pas le texte.

Un identifiant de nœud ne doit pas être un numéro de ligne

Rendre l'indice de ligne comme identifiant est tentant : tant qu'on ne fait qu'ajouter en fin, rien ne bouge et tout marche. Mais retirer ou insérer au milieu décale toutes les lignes au-dessus — les identifiants que l'appelant a gardés, la table des parents, et les clés remises à NSOutlineView. Le dépliement et la sélection passent alors d'un nœud à l'autre, un enfant s'accroche au mauvais parent, et rien ne lève.

Le remède tient en un type propre, pas en un entier plus stable : un numéro jamais réutilisé mais resté Integer aurait compilé partout et coïncidé avec la ligne jusqu'à la première suppression. NativeOutlineNode fait refuser par le compilateur chaque endroit qui confondait les deux. Et comme un indice qu'AppKit ne connaît pas lève une exception Objective-C, l'animation n'est tentée que sur un parent affiché et déplié ; ailleurs, l'arbre est rechargé.

Un dossier n'est pas forcément un dossier

FolderItem.IsFolder rend True pour une application, un .mpkg, une bibliothèque Photos, un projet Xcode, un document RTFD. macOS appelle cela un paquet et lui seul le sait : il faut interroger NSURLIsPackageKey, NSURLIsApplicationKey et NSURLContentTypeKey. Un .pkg moderne, lui, n'est pas un dossier du tout — c'est un fichier plat.

Deux pièges dans le détail. L'ordre des questions : un alias vers une application est d'abord un alias, une application est un paquet avant d'être un dossier. Et il faut résoudre les liens symboliques/Applications/Safari.app en est un, il passerait sinon pour un simple alias. Enfin, lisez les clés plutôt que de les recopier : NSURLIsApplicationKey vaut en réalité _NSURLIsApplicationKey, avec un tiret bas que rien n'annonce.

RealityKit est hors d'atteinte depuis Xojo

RealityKit remplace SceneKit depuis macOS 26, mais il n'expose aucune classe de vue à l'Objective-C : ni ARView, ni RealityView, ni Entity, ni ModelEntity. Vérifié à l'exécution — les seules classes ObjC du framework sont de l'interne Swift aux noms décorés (_TtC10RealityKit…). Ses en-têtes publics ne couvrent que les shaders Metal.

Xojo ne parlant que l'Objective-C, RealityKit ne s'atteint pas. SceneKit reste donc la seule voie praticable pour de la 3D en Xojo, tout déprécié qu'il soit — et il faudra le savoir le jour où Apple le retirera : le repli sera la vignette QuickLook, fixe.

La taille demandée à QLThumbnailImageCreate est une BOÎTE, et le 3D veut du 4:3

Le paramètre de taille n'est pas une consigne d'échelle mais une boîte dans laquelle la vignette doit tenir. Le générateur 3D rend du 4:3 : toute boîte plus étroite que ce rapport le fait échouer sans rien dire. Mesuré sur un STL — 840 × 340 rend Nil, 400 × 267 aussi, tandis que 512 × 512 rend 512 × 384 et 400 × 300 rend 400 × 300.

On demande donc un carré, qui contient n'importe quel rapport naturel, et l'on laisse la vue mettre à l'échelle. Au-delà de 1024 le générateur plafonne de lui-même. Le piège est vicieux parce que l'échec est silencieux et ressemble à « ce format n'est pas géré » : on retombe sur l'icône en croyant que QuickLook ne sait pas faire.

Fermer deux fois un QLPreviewView termine le processus en silence

close est définitif — la vue n'accepte plus rien ensuite — mais rien n'empêche de l'appeler une seconde fois, et cela fait disparaître l'application sans message, sans trace. Le cas arrive vite dès que deux chemins ferment : l'un au changement de page, l'autre avant de reconstruire.

Il faut donc un drapeau interne et le contrôler dans close comme chez l'appelant. Available() doit rendre False après fermeture, faute de quoi un appelant prudent se croira autorisé à fermer de nouveau.

Aperçu VIVANT ou VIGNETTE : la 3D rend le choix obligatoire

Un QLPreviewView installe une NSRemoteView servie par SceneKitQLPreviewExtension — un autre processus, qui de surcroît survit à son client et s'accumule. Sur un document 3D, cela détruit définitivement le glisser-déposer du processus : plus rien ne peut être glissé dans l'application, et le Finder refuse même de soulever un fichier. Ni close, ni la destruction de la vue, ni le changement de page n'y font quoi que ce soit — seule la sortie de l'application. Images, PDF, texte et son sont indemnes.

La vignette est la sortie : QLThumbnailImageCreate passe par SceneKitQLThumbnailExtension, celui que le Finder emploie sans cesse. Elle rend une image — aucune vue hors processus dans la fenêtre, aucun processus laissé derrière — avec le rendu 3D complet. Dépréciée depuis 10.15 mais toujours présente et synchrone (43 ms sur un STL), là où l'API moderne exige un bloc et un rappel hors du thread principal. Elle rend Nil sur les dossiers, les applications et les formats inconnus : on retombe alors sur l'icône du Finder, et la panne du jour où elle disparaîtra est déjà prévue.

Une classe hors AppKit n'existe pas tant qu'on ne charge pas son framework

QLPreviewView appartient à QuickLookUI, sous l'ombrelle Quartz — que Xojo ne lie jamais. Vérifié : un binaire qui ne lie pas Quartz ne trouve pas la classe, objc_getClass rend Nil. Il faut donc un dlopen explicite avant tout ClassRef.

Et sur le chemin complet : dlopen("Quartz") échoue, comme dlopen("AppKit") d'ailleurs — les noms courts que Xojo accepte dans un Lib ne sont pas ceux que dlopen résout. Bonne surprise en revanche : NSURL se conforme déjà au protocole QLPreviewItem, il n'y a aucune classe d'exécution à fabriquer.

Un mot-clé Xojo en membre d'énumération, et l'erreur accuse les usages

Soft est un mot-clé — celui de Soft Declare — et Xojo ignore la casse : Soft=1 dans un #tag Enum est une « Syntax error ». Le symptôme est trompeur au point d'être invalidant : Xojo signale chaque ligne qui écrit MonEnum.Soft et déclare le bloc de l'énumération sain, tant qu'il reste un usage à incriminer.

L'erreur ne tombe sur la déclaration qu'une fois toutes les références retirées. La règle à en tirer : quand une construction rigoureusement identique à du code qui compile est refusée, c'est un identifiant — et il faut aller lire la déclaration qu'il nomme, pas la ligne que le compilateur montre.

addRow: lève si la ligne racine n'est pas composée

Poser un prédicat simple sur un NSPredicateEditor le réduit à une seule ligne, sans racine composée. Le addRow: suivant ne reste pas inerte : il lève une NSRangeException dans -[NSRuleEditor _insertNewRowAtIndex:ofType:withParentRow:] — et une exception Objective-C termine le processus Xojo.

Le remède ne coûte rien : emballer le prédicat dans un ET à une seule sous-condition. Mesuré — la chaîne rendue par predicateFormat est identique, mais l'éditeur retrouve sa ligne composée. rowTypeForRow(0) permet de détecter l'état dangereux avant d'agir ; un éditeur vide, lui, accepte addRow: sans problème.

Un NSTableHeaderView à cadre nul est installé, et invisible

Masquer l'en-tête d'un tableau, c'est setHeaderView:nil — le NSScrollView replie alors la zone qu'il lui réservait. Le rendre en fabriquant un en-tête neuf marche aussi, à condition de lui donner une hauteur : à cadre nul il est bel et bien posé, le scroll view rétablit sa zone… d'une hauteur de zéro.

On ne voit donc rien, sans la moindre erreur pour le signaler. Mieux vaut garder l'en-tête d'origine — retenu, puisque setHeaderView:nil le relâche — que deviner une hauteur qui dépend du système et du style de table.

L'image de coche des menus est PARTAGÉE

paletteMenuWithColors:titles:selectionHandler: laisse aux pastilles l'image d'état ordinaire : NSMenuCheckmark, 18 × 17 points. Dessinée par-dessus une pastille d'environ 13 points, elle déborde et se retrouve rognée — on voit un arc blanc au lieu d'une coche.

Et la redimensionner sur place est exclu : deux palettes distinctes rendent le même objet, un item de menu ordinaire aussi. Il faut fabriquer une coche neuve par item — un symbole SF à la taille voulue, en mode template pour qu'elle se teigne selon le fond.

AppKit n'a pas d'alignement vertical - il faut placer le cadre

Un NSTextField centre son texte dans le cadre qu'on lui donne, et c'est tout : aucune propriété ne dit « en haut » ou « en bas ». L'alignement vertical d'une cellule s'obtient donc en plaçant le cadre du contrôle dans la cellule, pas en réglant quoi que ce soit.

Deux conséquences. L'origine d'une vue non flipped étant en bas à gauche, « en haut » veut dire le y le plus grand — l'inverse de l'intuition. Et le masque de redimensionnement doit se limiter à la largeur : laisser la hauteur suivre annulerait le placement qu'on vient de calculer.

Un style n'est pas un contrôle : où poser l'effet de bord de macOS 26

NSScrollEdgeEffectStyle n'a ni cadre ni vue : c'est un objet de style, et le SDK ne l'accepte que sur deux propriétés — preferredScrollEdgeEffectStyle de NSTitlebarAccessoryViewController et de NSSplitViewItemAccessoryViewController. En faire une classe de la bibliothèque aurait été du remplissage.

Il vit donc sur NativeWindowChrome, qui possède la fenêtre. SetScrollEdgeEffect rend le nombre d'accessoires effectivement stylés : zéro n'est pas une erreur mais le constat qu'il n'y en a aucun à styler — la fenêtre n'a d'accessoire de barre de titre que lorsque la barre de format RTF est ouverte.

Le double-clic de la table et l'édition d'une cellule visent le même geste

L'action de double-clic d'un NSTableView et le démarrage de l'édition d'un NSTextField logé dans une cellule répondent tous deux au second clic. Sur une colonne éditable ils se disputent la souris, et rien dans l'API ne le signale.

DoubleClickAction = False désarme l'action — un SEL nul passé à setDoubleAction:, et AppKit n'envoie plus rien. Même logique pour l'apparence : BezeledEditableCells choisit entre un champ qui ne se révèle qu'à la saisie (le renommage du Finder) et un champ qui s'annonce modifiable d'emblée. Aucune des deux n'est objectivement bonne, d'où l'option plutôt qu'un choix imposé.

Le tag d'un NSControl, pour retrouver la cellule qui agit

Quand une case à cocher ou un menu logé dans un tableau déclenche son action, le rappel ne reçoit que le contrôle — ni ligne, ni colonne. Le tag, un NSInteger libre sur tout NSControl, y porte l'indice plat de la cellule, le même que le stockage : ligne x colonnes + colonne.

On revient à l'un et l'autre par une division entière et un modulo. Un encodage du genre ligne x 1000 + colonne marcherait aussi, mais poserait une limite arbitraire ; réutiliser l'indice de stockage n'en pose aucune et ne laisse qu'une arithmétique à vérifier.

Un champ éditable prévient par DEUX chemins

L'action d'un NSTextField part sur Entrée ; controlTextDidEndEditing: part sur la perte du focus. Il faut les deux — on clique très souvent ailleurs sans valider — mais ils arrivent alors tous les deux pour une seule modification.

La parade n'est pas de choisir : c'est de ne rien faire quand la valeur n'a pas reellement changé. Le garde rend les deux chemins idempotents et l'événement ne part qu'une fois.

Une exception Objective-C ne se rattrape pas depuis Xojo

predicateWithFormat: lève une NSInvalidArgumentException sur une chaîne mal formée — vérifié. Un Try...Catch Xojo ne l'intercepte pas : l'exception traverse et termine le processus. Ce n'est pas une erreur qu'on gère, c'est un plantage.

Conséquence sur la forme de l'API : SetPredicateFormat ne doit recevoir que des chaînes produites par PredicateFormat, jamais une saisie d'utilisateur. La méthode le dit dans son propre commentaire plutôt que de le laisser découvrir.

Un NSSet n'a pas d'ordre - « le premier élément » n'existe pas

collectionView:didSelectItemsAtIndexPaths: rend un NSSet, pas un tableau. En tirer « le premier » indice n'a aucun sens : anyObject est le seul accès honnête quand on n'en veut qu'un.

La même prudence vaut pour selectionIndexPaths. Dès que la sélection multiple est permise, exposer un unique « index sélectionné » est une simplification qu'il faut assumer à voix haute.

Un NSCollectionViewItem n'a pas besoin de nib

Vérifié en Objective-C avant d'y compter : setView: sur un NSCollectionViewItem neuf fonctionne, et loadView n'est jamais appelé. C'est la ruse que NativeWindowChrome emploie déjà pour ses NSViewController, et elle évite tout le détour par un fichier d'interface.

Corollaire à ne pas oublier : un élément dont la vue est posée à la main ne dessine aucune sélection. Il faut la peindre soi-même depuis didSelect / didDeselect, en écrivant la couleur au moment du clic pour qu'elle soit résolue dans l'apparence courante.

L'IDE repose en silence un ancrage que la chrome interdit

Sous NSSplitViewController, la règle est : la taille par l'API Xojo — seul geste qui remet en page les enfants d'un DesktopPagePanel —, la position par AppKit. Pour que la seconde tienne, les vues de premier niveau du détail doivent avoir LockRight et LockBottom à False. Avec LockTop et LockBottom à True, Xojo tient la vue pour étirée du haut au bas de la fenêtre et la replace à Top = 0 — sous la barre d'outils — après le placement AppKit.

Le piège est qu'aucune ligne de code ne change : il suffit d'étirer un contrôle jusqu'au bord bas du conteneur dans le designer pour que l'IDE verrouille l'ancrage, sans rien dire. Le symptôme est franc — le titre de la page chevauche celui de la fenêtre, les libellés de la barre d'outils sont traversés par le contenu. Il se vérifie dans le .xojo_window, sur l'en-tête du bloc de premier niveau, avant tout Begin imbriqué. Remettre LockBottom à False ne perd pas la hauteur : l'événement DetailResized la recalcule à chaque passe.

Xojo est insensible à la casse : un identifiant qui ressemble à un mot-clé est le mot-clé

isa est l'opérateur IsA. sub, iF, dO, tO pareil. Et ce n'est pas réservé aux mots-clés : un paramètre nommé color masque le type Color, si bien que Color.RGB(0,0,0) devient une recherche de membre sur ce paramètre.

Une erreur de syntaxe sur la PREMIÈRE instruction d'une méthode arrête l'analyse de toute la classe : ses membres deviennent alors « inexistants » vu des autres classes, et son constructeur est rapporté avec un mauvais nombre d'arguments. Cinq erreurs pour un seul mauvais nom.

Le retain est tout le sujet

NSToolbar.delegate, NSToolbarItem.target, NSControl.target, NSTableView.dataSource, NSPopover.delegate : toutes des références faibles à remise à zéro. ObjCClass.CreateInstance rend donc Retain(init(alloc(cls))).

Sans ce retain, l'instance meurt aussitôt, la référence faible se vide, et aucun rappel ne part jamais. Le symptôme se lit comme « le runtime refuse les références faibles vers une classe créée dynamiquement ». Il ne les refuse pas ; l'objet était simplement désalloué.

La taille par l'API Xojo, la position par AppKit

Écrire DetailPanel.Width = w par la propriété Xojo est le seul geste qui remette les enfants du DesktopPagePanel en page. Puis corriger la position avec PlaceView, en coordonnées AppKit. Ne jamais lire la géométrie Xojo sous un split view controller — elle reste périmée.

Et retirer LockRight / LockBottom des vues de premier niveau : ce verrou est ce qui dit à Xojo « ce contrôle est à moi, je le redimensionne ». Sans quoi Xojo relayoute aussi, contre la largeur de la FENÊTRE, et vous voyez deux passes de mise en page.

reloadData désélectionne

Quatre façons de rafraîchir une liste, et prendre la mauvaise fabrique des bugs. L'appeler depuis la notification de changement de sélection vide la sélection juste avant que l'événement ne lise l'indice — le symptôme se lit « le clic ne fait rien ».

Et un simple setNeedsDisplay: ne fait PAS relire un getter redéfini comme isEmphasized : seul un vrai rechargement le fait, d'où ReloadPreservingSelection.

NSToolbarItemGroup : l'ordre du câblage est tout

AppKit route le clic d'un groupe vers le sous-item, jamais vers le groupe. Mais écrire target/action sur un sous-item DÉJÀ assemblé termine le processus à la première vraie passe de mise en page, sans exception ni événement Closing.

La séquence qui marche : setSubitems: avec un tableau vide → câbler chaque sous-item → setSubitems: avec la liste complète.

ObjCBlock est fourni par Xojo depuis 2019r2

New ObjCBlock(theDelegate As Object) puis .Handle. Le Delegate prend les arguments déclarés du bloc, sans le pointeur de bloc en tête ; bâti sur une méthode d'instance, il porte l'objet avec lui, donc pas besoin du registre de Cocoa.

Pour une API asynchrone, le bloc, son delegate ET l'objet propriétaire doivent tenir dans des PROPRIÉTÉS jusqu'au rappel — jamais des variables locales.

sizeToFit n'existe que sur NSControl

L'appeler sur une NSView simple lève un sélecteur inconnu. NativeSlider.Handle rend une vue hôte composite dès qu'il y a des icônes : NativeControlHost.Center conditionne donc l'appel à Cocoa.Responds.

NSTextAlignment n'a pas les mêmes valeurs selon l'architecture

Le SDK bascule sur TARGET_ABI_USES_IOS_VALUES : sur Apple Silicon, Centre = 1 et Droite = 2 ; sur Intel, l'inverse. D'où les #If TargetARM dans les pastilles et NativeTextField.SetAlignment.

Le SDK 26 a renommé tout NSBezelStyle

RoundedPush, RegularSquareFlexiblePush, TexturedRoundedToolbar, RoundRectAccessoryBarAction, RecessedAccessoryBar, InlineBadge. Les anciens noms ne sont plus que des alias dépréciés.

Et setButtonType: REMET le bezel et l'image à des valeurs propres au type : à appeler AVANT de régler BezelStyle, jamais après.

Trois API où la valeur n'est pas encore là où vous la cherchez

comboBoxSelectionDidChange:stringValue n'est pas encore à jour, AppKit recopie l'élément choisi APRÈS le rappel : lire objectValueOfSelectedItem. clickedPathItem — valide UNIQUEMENT pendant l'envoi de l'action. NSAlert.suppressionButton — à lire APRÈS RunModal.

NSAlert : l'ordre d'ajout, pas l'ordre à l'écran

Le premier bouton ajouté est le bouton par défaut, donc celui de droite, celui que Retour déclenche. Avec une action destructrice il faut donc déplacer l'équivalent clavier — une action irréversible ne doit jamais partir par réflexe.

Et NSAlert n'a pas de notion de « destructif » : ce sont ses boutons qui l'ont, buttons étant un tableau de NSButton.

La barre RTF n'appartient pas à l'éditeur, mais à la fenêtre

usesInspectorBar installe un NSTitlebarAccessoryViewController sur la fenêtre — vue __NSInspectorBarView, 28 points, sous la barre d'outils et sur toute la largeur — et rétrécit la vue de contenu d'autant. Elle ne peut donc pas être confinée dans un cadre : elle est au niveau de la fenêtre, exactement comme dans TextEdit.

Toute mise en page qui positionne ses vues elle-même doit être refaite après l'appel, sinon la barre recouvre le contenu au lieu de le pousser. Et contrairement à ce qu'on suppose volontiers, ni le scroll view ni l'ordre des appels n'y changent rien — vérifié en Objective-C sans scroll view, réglé avant setDocumentView:, puis hors fenêtre : l'accessoire est installé dans les trois cas. Pour une barre dans le cadre il faut une autre voie : la barre du composant, ou l'accessoire de règle ci-dessous.

L'accessoire de règle plante si le client n'est pas posé d'abord

C'est la seule façon native de loger une barre dans la zone de texte : l'accessoire devient sous-vue de la NSRulerView, donc du scroll view, sans toucher à la fenêtre. Mais setAccessoryView: lève une exception si le clientView de la règle n'a pas été posé avant — « you must set the client view of the ruler before you can have an accessory view ». Ce n'est pas un appel sans effet, c'est un plantage.

Et la règle graduée vient avec : 60 points mesurés pour 28 d'accessoire. Pour une barre seule dans un cadre, celle de NativeRichTextEditor reste préférable.

Une commande de formatage part au premier répondant

changeFont: et changeColor: ne visent pas le contrôle qu'on croit : le panneau Police et le panneau Couleurs les envoient au premier répondant. Sans makeFirstResponder préalable, la commande part dans le vide, sans erreur.

Auto Layout et placement par cadre : ce qui se règle tout seul, et ce qui ne se règle pas

NSGridView et NSStackView travaillent en Auto Layout, alors que toute la bibliothèque place par cadre. Vérifié en Objective-C : construits par initWithFrame:, tous deux gardent translatesAutoresizingMaskIntoConstraints à YES — ils se placent donc par cadre comme le reste. Et addRowWithViews: comme addArrangedSubview: mettent ce drapeau à NO sur les vues qu'on leur confie : l'appelant n'a rien à régler.

Deux réserves. La fabrique de classe stackViewWithViews:, elle, rend une pile à NO — elle ignorerait son cadre ; d'où initWithFrame: dans le constructeur. Et fittingSize s'exprime en rectangles d'alignement : le cadre d'un NSButton déborde du sien de quelques points, donc une grille de boutons ajustée au pixel près paraît rognée — Refit prend un supplément pour cela.

Deux classes runtime de même nom : le sélecteur disparaît sans un mot

ObjCClass réutilise une classe déjà enregistrée — c'est voulu, et c'est ce qui évite la prolifération d'une fenêtre à l'autre. Mais si deux classes différentes demandent le même nom, la seconde hérite de la première et son AddMethod est un no-op silencieux : sa cible ne répond jamais à son sélecteur.

Le symptôme ne pointe nulle part. Un menu s'ouvre, on choisit un item, popUpMenuPositioningItem: rend YES — un item A bien été choisi — et rien ne se passe : l'action est partie au néant faute de répondant. Depuis, AddMethod vérifie sur une classe réutilisée que le sélecteur y est réellement, et lève sinon. Arrivé une fois, entre NativeMenuToolbarItem et NativeMenu, tous deux sur « VDSMenuTarget ».

Le menu palette ne peut pas être déroulé seul

Un menu en presentationStyle Palette doit être le sous-menu d'un item appartenant à un menu ordinaire. L'en-tête est net : il ne peut être ni ouvert par popUpMenuPositioningItem:, ni attaché directement à un menu surgissant ou à un item de barre d'outils. AddColorPalette impose donc cette forme — on lui donne le titre de l'item porteur, pas un menu à part.

Bonne nouvelle en revanche : son gestionnaire de sélection est facultatif. On passe Nil et on lit selectedItems après coup, ce qui évite d'avoir à fabriquer un bloc Objective-C. Et selectionMode n'agit qu'à l'intérieur d'un GROUPE — les items entre deux séparateurs.

Un événement Boolean non implémenté rend False

Ce détail dicte le nom des événements d'une bibliothèque. Un Event WillDrag() As Boolean aurait interdit tout glissement tant que l'appelant ne l'écrit pas — le contraire de ce qu'on attend d'un réglage par défaut.

D'où CancelDrag, inversé : rendre True annule, et ne rien écrire laisse passer. NativeDropView garde au contraire Dropped au sens direct, parce qu'un dépôt doit être traité pour avoir un sens.

Une sélection programmée prévient le délégué

selectRowIndexes:byExtendingSelection: déclenche tableViewSelectionDidChange: exactement comme un clic — NativeSidebar.SelectPage suffit donc à faire suivre la page, sans la pousser une seconde fois.

Avec une réserve mesurée : AppKit ne notifie pas une sélection inchangée. Viser la ligne déjà sélectionnée ne produit aucun événement — ce qui est correct, rien n'a bougé, mais un appelant qui comptait sur l'événement pour se synchroniser doit le savoir.

L'origine d'une vue non flipped est en bas à gauche

La frame d'un NSDraggingItem est exprimée dans les coordonnées de la vue qui ouvre la session. La laisser à (0,0) ne met pas la vignette « au début » : elle la colle dans le coin inférieur gauche, loin du curseur.

Pour qu'elle suive la souris : convertPoint:fromView: avec Nil — qui signifie « depuis les coordonnées de la fenêtre » — sur le point rendu par locationInWindow, puis un décalage d'une demi-vignette pour la centrer. Vérifiable sans souris : une vue en (100,50), un curseur en (180,110) dans la fenêtre, et l'on doit lire (80,60).

Un CGPoint par valeur se lit comme deux Double

Les sélecteurs de source de glissement — hitTest:, draggingSession:endedAtPoint:operation: — annoncent un CGPoint passé par valeur. Deux Double consécutifs occupent exactement les mêmes registres que la structure : le délégué Xojo peut donc les recevoir séparément, sans déclarer de structure.

Vérifié en Objective-C plutôt que supposé : une méthode installée avec l'encodage "@@:{CGPoint=dd}" mais implémentée comme (id, SEL, double, double) reçoit bien les bonnes valeurs.

Ce qu'on dépose n'est pas forcément un fichier

Un FolderItem issu d'un dépôt sait s'il est un dossier — IsFolder. Écrire « fichier » pour tout est une facilité, pas une limite du glisser-déposer.

Avec une nuance : un paquet — .app, .pkgest un répertoire, donc IsFolder le compte parmi les dossiers. Pour le traiter comme un document, ce que fait le Finder, il faut regarder son extension. L'icône rendue par NSWorkspace.iconForFile:, elle, montre déjà la différence.

Deux façons de lire une constante exportée, et elles ne s'échangent pas

dlsym rend l'adresse du symbole. Pour une constante NSString — identifiant d'item de barre d'outils, type de presse-papiers — le symbole contient un pointeur vers l'objet : il faut déréférencer, slot.Ptr(0). Pour un symbole déclaré comme un tableau, tel _NSConcreteGlobalBlock, l'adresse est l'objet : déréférencer donnerait n'importe quoi.

D'où Cocoa.ExportedString pour le premier cas, et l'écriture directe pour le second. Les deux tournent dans la bibliothèque, à trois lignes d'écart.

Ce que le système ne retient pas pour vous

Un NSStatusItem disparaît dès que la variable qui le tient sort de portée : la barre de menus ne le retient pas. Et Remove n'est pas optionnel — sans lui, l'extra reste dans la barre jusqu'à la fin du processus, même l'objet Xojo détruit.

Même famille que les blocs asynchrones et les cibles d'action : dès qu'AppKit ne détient qu'une référence faible, ou aucune, c'est une PROPRIÉTÉ qu'il faut, jamais une locale.

Un NSOutlineView EST un NSTableView

La chaîne se lit au runtime : NSOutlineView → NSTableView → NSControl → NSView. Une arborescence n'est donc pas un contrôle voisin du tableau, c'est un tableau qui indente sa première colonne. En écrire deux classes indépendantes coûte deux fois le code des cellules, et la seconde finit toujours la plus pauvre : l'arbre n'avait ni case à cocher, ni menu, ni cellule éditable, ni couleur, ni alignement, ni en-tête — rien qu'AppKit interdisait, seulement ce que la duplication avait laissé de côté.

Faire hériter a supprimé dix implémentations jumelles et n'a laissé que dix redéfinitions : les sélecteurs de la source de données, la colonne qui porte les triangles de repli, le vidage, le refus du tri, la traduction ligne visible ↔ ligne de stockage, l'ajout de ligne devenu ajout de nœud, et trois relais qui lèvent en plus l'événement du nœud. La même parenté vaut ailleurs dans la bibliothèque : NativeSidebar et NativeOutlineSidebar tiennent de NativeSidebarBase, et quatre items de barre d'outils de NativeToolbarItem.

Xojo répartit les appels depuis Super.Constructor

Une redéfinition de sous-classe est bien atteinte depuis le constructeur de la classe de base : l'objet porte sa classe réelle dès l'allocation — modèle Java, pas C++. C'est ce qui permet à un constructeur unique de bâtir le commun et de laisser la sous-classe fournir ses différences. Une condition : la redéfinition ne doit toucher qu'à ses paramètres, les propriétés de la sous-classe n'étant pas encore posées à cet instant.

Et il faut le constater, pas le supposer. Un repli silencieux sur l'implémentation de base ne lève rien : on obtient un contrôle qui ne dessine simplement rien, symptôme trop discret pour qu'on remonte jusqu'à sa cause. Un Cocoa.Responds(mDelegate, "<sélecteur ajouté par la redéfinition>") juste après la construction, suivi d'un System.DebugLog en cas d'échec, change la supposition en constat pour le prix d'un appel.

Un repli n'est pas « ne rien faire »

Tout ce qui date de macOS 26 est posé derrière un Cocoa.Responds — le SÉLECTEUR interrogé, jamais le numéro de version. Mais la question suivante compte autant : que fait-on quand il est absent ? Pour une forme de bordure ou une prominence de teinte, ne rien faire est juste — le contrôle garde son aspect, et l'application est simplement moins fine. Pour placeholderStrings, ne rien faire laisserait le champ sans aucune invite : ce n'est plus une dégradation, c'est une régression. On y pose donc la PREMIÈRE des invites.

La règle se lit en une phrase : le repli doit rendre le meilleur comportement disponible, pas l'absence de comportement. Un test de sélecteur qui protège du plantage tout en cassant la fonction n'a fait que déplacer le défaut.

Une propriété de NSView appartient à toutes les classes

prefersCompactControlSizeMetrics (macOS 26) est déclarée sur NSView, pas sur un contrôle particulier : elle vaut donc pour les vingt-et-une classes que la bibliothèque enveloppe. La recopier dans chacune serait vingt fois la même ligne à corriger le jour où elle change. Elle est posée UNE fois, en méthode partagée de NativeControlHost, qui prend le Handle de n'importe quel contrôle.

Même raisonnement pour les énumérations : NSControlBorderShape sert à NSButton et à NSSegmentedControl, NSTintProminence à NSButton et à NSSlider. Les deux vivent dans NativeControlHost et les classes s'y réfèrent — la même raison qui fait qu'une arborescence hérite d'un tableau plutôt que de le recopier.

Lire le SDK, et sonder plutôt que supposer

Les seuils de NSLevelIndicator ne sont documentés que dans un sens — « values above the warning threshold ». Il n'existe aucun moyen documenté de les inverser : tout autre sens se peint à la main via fillColor.

Et quand un réglage « ne change rien » à l'écran : pousser une valeur absurde et reconstruire UNE fois. Si ça bouge, le chemin de code est vivant et les retouches étaient trop subtiles ; sinon, le binaire qui tourne n'est pas le code édité.

Core

Le pont vers le runtime Objective-C, et la mécanique qui loge une NSView dans une fenêtre Xojo.

Core

Cocoa

module

Module de base : déclarations, structures NSRect / NSSize / NSEdgeInsets, conversion des chaînes, et le registre de propriétaires qui permet à un rappel Shared — qui ne reçoit qu'un pointeur nu — de retrouver son objet Xojo.

Méthodes

Sub AddSubview(parent As Ptr, child As Ptr)
Function Alloc(cls As Ptr) As Ptr
Sub ApplyColor(tv As Ptr, c As Color)
Function Autorelease(obj As Ptr) As Ptr
Rend la propriété d'un objet SANS le détruire tout de suite : le pool le relâchera à la fin du passage de boucle courant. C'est ce qu'il faut quand on doit remettre un objet à AppKit — lui le retiendra pour son propre compte, mais APRÈS notre retour.Un release immédiat détruirait l'objet avant qu'AppKit l'ait pris ; ne rien faire le fait fuir. L'autorelease est le seul des trois qui soit juste. Rend l'objet, pour s'écrire en fin d'expression : Return Autorelease(v).
Function BuildRichTextEditor(hostView As Ptr, width As Double, height As Double) As Ptr
Crée un NSScrollView + NSTextView (rich text) et l'ajoute à la vue hôte (le NSView du DesktopCanvas). Renvoie le pointeur de la NSTextView (à conserver pour piloter le formatage).
Function ClassRef(name As String) As Ptr
Function ConvertFontTrait(fm As Ptr, font As Ptr, trait As UInteger) As Ptr
Function DataWithContentsOfFile(path As String) As Ptr
Sub ExportRTF(tv As Ptr, file As FolderItem)
Function FontOfSelection(tv As Ptr) As Ptr
Function FromNSStr(p As Ptr) As String
NSString * -> String Xojo, SANS CFStringRef.Un retour déclaré CFStringRef fait que Xojo prend possession de l'objet et le libère. Or -[NSString description] renvoie self sans incrémenter le compteur : chaque appel sur une chaîne appartenant à AppKit la sur-libère, et la casse se manifeste plus tard, ailleurs. On passe donc par UTF8String, qui ne transfère aucune propriété. Le retour d'un declare CString ne se convertit pas implicitement dans un appel de méthode d'extension : il faut l'affecter d'abord.
Sub ImportRTF(tv As Ptr, file As FolderItem)
Function InitWithFrame(obj As Ptr, frame As NSRect) As Ptr
Function NSColorRGBA(r As Double, g As Double, b As Double, a As Double) As Ptr
Function MacOSVersionAtLeast(major As Integer, minor As Integer = 0) As Boolean
Version du système d'exploitation, lue une seule fois. À n'utiliser que pour de la présentation : pour décider si une API existe, Responds() est plus sûr — un sélecteur présent est une preuve, un numéro de version une supposition.
Function MainQueue() As Ptr
La file principale de GCD.dispatch_get_main_queue() n'est pas une fonction mais une macro qui désigne la structure exportée _dispatch_main_q : on lit l'ADRESSE du symbole, et cette adresse EST la file. Nuance inverse de ExportedString, où le symbole contient un pointeur qu'il faut déréférencer.
Sub PerformOnMainThread(callback As Ptr, context As Ptr)
Fait exécuter un rappel sur le fil de l'interface, plus tard, sans attendre.Les blocs de complétion d'Apple arrivent sur une file de service, pas sur le fil de l'interface, et le moteur Xojo n'est pas prévu pour être réveillé depuis un fil qu'il ne connaît pas. Le bloc range un pointeur, pose un drapeau, et repasse par ici. callback est un AddressOf sur une méthode Shared prenant un Ptr.
Function Responds(obj As Ptr, selectorName As String) As Boolean
L'objet répond-il à ce sélecteur ? C'est LA façon de tester la présence d'une API : elle constate au lieu de supposer.
Function ExportedString(symbolName As String) As String
Lit une constante NSString exportée par AppKit — identifiant d'item de barre d'outils, type de presse-papiers — plutôt que d'en recopier la valeur. Elles ne suivent pas toutes la même convention, et une chaîne recopiée devient fausse sans prévenir le jour où Apple la change.NUANCE : dlsym rend l'ADRESSE du symbole, et le symbole CONTIENT un pointeur vers la NSString — d'où le déréférencement slot.Ptr(0). Pour un symbole déclaré comme un tableau, au contraire, l'adresse EST l'objet.
Function NSStr(s As String) As Ptr
Function OwnerOf(handle As Ptr) As Object
Retrouve l'objet Xojo propriétaire d'une instance ObjC créée au runtime. Utilisé depuis les méthodes Shared de callback, qui ne reçoivent que le « self » ObjC.
Sub RegisterOwner(handle As Ptr, owner As Object)
Associe une instance ObjC (delegate, dataSource, target…) à son propriétaire Xojo. La référence est faible : l'enregistrement ne maintient pas l'objet Xojo en vie.
Sub ReplaceRangeWithRTF(tv As Ptr, range As NSRange, data As Ptr)
Function RTFFromRange(tv As Ptr, range As NSRange) As Ptr
Function SelectedRange(tv As Ptr) As NSRange
Sub SetAllowsUndo(tv As Ptr, flag As Boolean)
Sub SetAutoresizingMask(view As Ptr, mask As UInteger)
Sub SetDocumentView(scroll As Ptr, view As Ptr)
Sub SetEditable(tv As Ptr, flag As Boolean)
Sub SetFontRange(tv As Ptr, font As Ptr, range As NSRange)
Sub SetHasVerticalScroller(scroll As Ptr, flag As Boolean)
Sub SetRichText(tv As Ptr, flag As Boolean)
Sub SetTextColorRange(tv As Ptr, color As Ptr, range As NSRange)
Sub SetViewFrame(view As Ptr, frame As NSRect)
Repose un cadre relevé par ViewFrame. Sert quand Xojo REMPLACE une vue et place mal celle qu'il vient de créer — basculer Password sur un DesktopTextField détruit la vue, en crée une autre, et celle-ci se retrouve à des coordonnées qui ne sont pas les siennes.Toujours la même règle : la taille par l'API Xojo, la position par AppKit.
Function SharedFontManager() As Ptr
Function TextLength(tv As Ptr) As UInteger
Sub ToggleTrait(tv As Ptr, mask As UInteger)
mask : NSItalicFontMask=1, NSBoldFontMask=2
Function TraitsOfFont(fm As Ptr, font As Ptr) As UInteger
Sub UnderlineSelection(tv As Ptr)
Sub UnregisterOwner(handle As Ptr)
Function ViewFrame(view As Ptr) As NSRect
Le cadre RÉEL d'une vue, à comparer à ce que Xojo croit avoir posé. Un écart signale que la vue a été déplacée dans le dos de l'un des deux.y se compte depuis le bas chez AppKit et depuis le haut chez Xojo : un écart sur y n'est pas forcément une anomalie, un écart sur x ou sur la largeur en est une.
Function WriteDataToFile(data As Ptr, path As String) As Boolean
Core

NativeColor

classe

Les 54 couleurs SÉMANTIQUES de macOS, celles qui portent un rôle plutôt qu'une teinte. Ce sont les seules qui suivent le mode sombre, la teinte d'accentuation choisie par l'utilisateur et les réglages d'accessibilité — toute valeur RVB écrite en dur les ignore. Un seul performSelector: plutôt que cinquante Declares typés à la main, qui seraient cinquante occasions de fautes de frappe.

Méthodes

Shared Function Handle(kind As Kinds) As Ptr
Le NSColor VIVANT, à passer tel quel à AppKit. Il reste dynamique : il se résout à chaque dessin, donc il suit un changement d'apparence sans qu'on ait à le reposer. C'est la forme à préférer dès que la couleur part vers une vue. Rend Nil si la couleur n'existe pas sur ce système.
Shared Function Value(kind As Kinds, fallback As Color = &c000000) As Color
La couleur RÉSOLUE, pour le dessin côté Xojo.C'est un INSTANTANÉ : la valeur est résolue dans l'apparence courante et n'en bougera plus. Passer en mode sombre ne la met pas à jour, il faut la relire et redessiner. Limite de la conversion, pas de l'implémentation — un Color de Xojo est trois octets, il ne peut rien porter de dynamique. L'alpha est conservé, et il le faut : les libellés secondaire à quinaire, le séparateur et les cinq remplissages sont semi-transparents par construction ; chez Xojo, Alpha vaut 0 pour opaque et 255 pour transparent.
Shared Function Available(kind As Kinds) As Boolean
La disponibilité lue PAR SÉLECTEUR, pas déduite d'un numéro de version — la doctrine du reste de la bibliothèque. La palette s'échelonne de 10.8 à 14.0 : quinaryLabelColor en 11.0, systemCyanColor en 12.0, textInsertionPointColor et les cinq remplissages en 14.0.
Shared Function SelectorName(kind As Kinds) As String
Le nom AppKit de la couleur. Utile à l'affichage et au journal : il dit exactement quelle API est en jeu, ce qu'un nom d'énumération traduit ne dirait pas.
Core

ObjCClass

classe

Fabrique de classes Objective-C au runtime. Contrairement aux implémentations qui suffixent _1, _2, celle-ci interroge d'abord objc_getClass et réutilise une classe déjà enregistrée ; AddMethod devient alors sans effet. Déterministe, et pas de prolifération de classes d'une fenêtre à l'autre.

Constructeur

Sub Constructor(className As String, superClassName As String = "NSObject")

Méthodes

Sub AddMethod(selectorName As String, handle As Ptr, signature As String)
Greffe une implémentation Xojo (AddressOf d'une méthode Shared) sur la classe. La signature est l'encodage de types ObjC : type de retour, puis "@:" (self et _cmd), puis un caractère par argument.q=Int64 d=Double @=id c/B=BOOL v=void cf. Objective-C Runtime Programming Guide, « Type Encodings ».
Sub AddProtocol(protocolName As String)
Déclare la conformité formelle. Facultatif : AppKit interroge de toute façon respondsToSelector:. Sans effet si le protocole n'est pas visible du runtime.
Function CreateInstance() As Ptr
Renvoie une instance RETENUE. Le retain n'est pas une précaution, c'est la condition de fonctionnement : delegate, dataSource et target d'AppKit sont des références faibles zeroing. Sans propriétaire fort, l'instance est désallouée aussitôt, la référence faible repasse à Nil, et aucun callback n'arrive jamais. L'appelant est responsable du ReleaseInstance correspondant.
Function Handle() As Ptr
Le pointeur de Class, pour alloc/init manuel (sous-classes de vues, par exemple).
Function IsNew() As Boolean
False si la classe préexistait et a été réutilisée telle quelle.
Shared Sub ReleaseInstance(obj As Ptr)
Function Responds(selectorName As String) As Boolean
Contrôle de cohérence : la classe expose-t-elle bien le sélecteur greffé ?
Shared Function MetaClassOf(cls As Ptr) As Ptr
La métaclasse porte les méthodes de CLASSE : c'est elle qu'il faut interroger pour savoir si une fabrique du type +itemWithFoo: existe sur cette version.
Shared Function SelectorFor(selectorName As String) As Ptr
Core

NativeControlHost

classe

Loge une vue AppKit à l'intérieur de la vue d'un contrôle Xojo servant d'ancre — un DesktopCanvas vide, typiquement. C'est ce qui évite toute la question de la géométrie : Xojo continue de placer l'ancre, le masque d'autoresizing fait suivre la vue AppKit, et il n'y a rien à resynchroniser.

Méthodes

Shared Sub Center(anchor As DesktopUIControl, view As Ptr)
Même principe que Fill, mais la vue garde sa taille propre et reste centrée. Pour un contrôle à taille intrinsèque — un NSSwitch, par exemple, dont l'étirement n'aurait aucun sens.
Shared Sub Detach(view As Ptr)
Shared Function MakeFlippedContainer(width As Double, height As Double) As Ptr
Comme MakeContainer, mais INVERSÉE : y compte depuis le haut, comme dans le reste de la bibliothèque et comme dans le concepteur Xojo.isFlipped n'est pas réglable, il faut le redéfinir — d'où la classe créée au runtime. ObjCClass réutilise une classe déjà enregistrée, donc plusieurs appelants peuvent la demander sans la dupliquer.
Shared Function MakeContainer(width As Double, height As Double) As Ptr
Une NSView nue, pour les endroits qui n'acceptent QU'UNE vue là où il en faudrait plusieurs : la vue accessoire d'un panneau de fichiers ou d'une alerte, le contentView d'un NSGlassEffectView.La vue est RETENUE : c'est à l'appelant de la ranger dans une propriété et de la rendre par Cocoa.ObjCClass.ReleaseInstance. Coordonnées AppKit, origine en bas — y compris pour ce qu'on y ajoute.
Shared Sub SetFrame(view As Ptr, x As Double, y As Double, width As Double, height As Double)
Pose le cadre d'une vue AppKit sans l'ajouter nulle part — pour préparer une vue destinée à un conteneur qui la placera lui-même : contentView d'un NSGlassEffectView, vue accessoire d'une NSAlert.Coordonnées AppKit, donc origine EN BAS, sauf si la vue parente est inversée — c'est le cas de celle d'un NativePopover, pas des autres.
Shared Sub Fill(anchor As DesktopUIControl, view As Ptr)
Place une vue AppKit DANS la vue d'un contrôle Xojo servant d'ancre — un DesktopCanvas vide, typiquement — et la laisse l'occuper entièrement.Héberger À L'INTÉRIEUR de l'ancre plutôt qu'à côté d'elle évite tout le problème de géométrie : c'est Xojo qui continue de placer et dimensionner l'ancre, et le masque d'autoresizing fait suivre la vue AppKit. On ne calcule aucune position, donc rien à resynchroniser au redimensionnement.
Shared Sub SetCompactMetrics(view As Ptr, compact As Boolean)
macOS 26 : demande à une vue — et à tout ce qu'elle contient — les métriques COMPACTES du système. C'est une propriété de NSView, donc valable pour n'importe quel contrôle enveloppé : d'où sa place ici plutôt que recopiée dans chaque classe.
Shared Sub SetSelectionAnchor(view As Ptr, x As Double, y As Double, width As Double, height As Double)
macOS 15. Déclare OÙ se trouve la sélection dans la vue : le système y pose le menu contextuel du clavier et les popovers, au lieu du centre. Ne vaut que pour les vues fabriquées par MakeFlippedContainer — une classe système ne peut pas recevoir la méthode sans être sous-classée.
Shared Sub ClearSelectionAnchor(view As Ptr)
Plus de sélection : le système revient au centre de la vue.

Énumérations

BorderShapesAutomatic=0Capsule=1RoundedRectangle=2Circle=3
TintProminencesAutomatic=0None=1Primary=2Secondary=3
Core

VDSLicence

classe

Le contrôle de licence. L'exécution depuis l'IDE est libre : la vérification est posée derrière #If DebugBuild, donc elle n'est même pas compilée sous l'IDE. Une application CONSTRUITE sans licence valide s'exécute, mais toute fenêtre qui emploie VDSTools porte une mention — chrome, contrôle posé dans l'IDE ou vue AppKit hébergée. Une seule exception : l'application de démonstration de l'éditeur, reconnue à son IDENTIFIANT de paquet, sans clé — une clé posée dans une application distribuée se lit dans son binaire et sert ailleurs telle quelle.

Méthodes

Shared Sub SetLicence(licensee As String, key As String)
À appeler dans App.Opening, AVANT qu'une fenêtre ne soit habillée. Le nom doit être recopié EXACTEMENT tel qu'il figure sur la licence : il entre dans le calcul du code, une espace en trop suffit à le refuser. Deux chaînes vides = pas de licence.
Shared Function Licensed() As Boolean · LicensedTo · StatusText · Notice
L'état, le nom du licencié, et les textes prêts à afficher dans un « À propos ».
Shared Function Inspect(licensee As String, key As String, ByRef majorCovered As Integer, ByRef reason As String) As Boolean
Vérifie une clé sans la poser, et dit POURQUOI elle est refusée — longueur, préfixe, signature. C'est ce qu'emploie le générateur.
Shared Function MakeLicence(licensee As String, majorCovered As Integer) As String
Fabrique une clé — l'affaire du générateur, pas de l'application. Clé de 33 caractères, VDS01-XXXXXX-… : HMAC-SHA256 tronqué à 120 bits, en base32 sans les lettres I, L, O ni U.
Shared Sub ApplyWatermark(window As Ptr)
Le filigrane des versions non licenciées : une pastille claire à liseré, texte noir gras, en bas à droite. Une par fenêtre, posée aussi par MarkHost, que la bibliothèque appelle depuis l'hébergement des vues et depuis l'Opening des contrôles posés dans l'IDE.Le fond est translucide par son CALQUE et non par l'alpha de la vue, sans quoi le texte pâlirait avec lui. La vue rend Nil depuis hitTest: : elle ne prend aucun clic.

Window

Le NSSplitViewController qui devient propriétaire de la fenêtre.

Window

NativeWindowChrome

classe

Installe un NSSplitViewController comme contentViewController de la fenêtre : barre latérale, volet de détail, inspecteur repliable, titre et sous-titre natifs, zone sûre sous la barre d'outils.

Constructeur

Sub Constructor(win As DesktopWindow)

Méthodes

Function DetailHeight() As Double
Function DetailWidth() As Double
Function HasInspector() As Boolean
Sub Install(sidebarView As Ptr, sidebarWidth As Double, minWidth As Double = 180, maxWidth As Double = 340)
Confie le contentViewController de la fenêtre à un NSSplitViewController : le contentView de Xojo devient la vue du volet de détail, la vue passée en argument celle du volet de sidebar.Ce que ce montage apporte gratuitement : vibrance et repli animé du volet sidebar, item de toolbar « toggle » système via la responder chain, césure de toolbar automatique, et gestion de la safe area (donc aucun inset à compenser sous la titlebar).
Sub InstallInspector(inspectorView As Ptr, width As Double, minWidth As Double = 200, maxWidth As Double = 420)
Troisième volet, à droite. inspectorWithViewController: (macOS 14+) apporte le même traitement système que la sidebar : repli animé, et surtout les identifiants NSToolbarToggleInspectorItem / NSToolbarInspectorTrackingSeparatorItem qui fonctionnent alors sans une ligne de code.
Function IsInspectorCollapsed() As Boolean
Function IsSidebarCollapsed() As Boolean
Shared Function MakeTitleView(title As String, subtitle As String = "") As Ptr
Titre + sous-titre empilés, à poser comme VUE d'un item de toolbar.Pourquoi : NSWindow.title est placé par AppKit en TÊTE de barre, donc du côté de la barre latérale. Pour l'aligner sur le début du détail — ce que font les applications système — il faut un item, que l'on place soi-même juste après le séparateur de suivi. Dans ce cas on masque le titre système (chrome.TitleVisible = False) pour ne pas l'afficher deux fois.
Sub PlaceView(v As Ptr, x As Double, y As Double, w As Double, h As Double)
Placement en coordonnées AppKit : origine EN BAS à gauche, le contentView de Xojo n'étant pas « flipped ». À n'utiliser que pour la POSITION — la taille doit passer par la propriété Xojo, voir l'événement DetailResized.
Sub Relayout()
Deux temps, et l'ordre compte : 1) la TAILLE est annoncée à la fenêtre (event), qui l'écrit via les propriétés Xojo — c'est le seul geste qui déclenche la remise en page des contrôles enfants d'un PagePanel ; 2) la fenêtre corrige ensuite la POSITION avec PlaceView, la géométrie Xojo étant fausse sous NSSplitViewController. Les vues de premier niveau du détail doivent avoir LockRight et LockBottom à False dans le designer, faute de quoi Xojo les remet en page de son côté et l'on voit deux passes se succéder.
Function SafeAreaTop() As Double
Hauteur occupée par la titlebar et la barre d'outils AU-DESSUS du détail.Avec FullHeightSidebar, le volet de détail monte jusqu'en haut de la fenêtre : sans ce décalage, le contenu passe sous la barre d'outils. safeAreaInsets (macOS 11+) donne la valeur exacte, qui varie avec le style de barre et le mode d'affichage — la coder en dur serait faux dès qu'on change de style.
Function ScrollEdgeEffectAvailable() As Boolean
macOS 26. On interroge la CLASSE de style, pas le numéro de version : un sélecteur présent est une preuve, un numéro de version une supposition.
Function SetScrollEdgeEffect(style As ScrollEdgeStyles) As Integer
NSScrollEdgeEffectStyle (macOS 26) : la façon dont le contenu s'efface sous une barre de titre ou un volet quand on fait défiler — bord doux, ou coupe franche.Ce n'est PAS un contrôle mais un objet de style, et il ne se pose que sur des contrôleurs ACCESSOIRES : ceux de la barre de titre et ceux des volets. On l'applique donc à tous les accessoires de titre de la fenêtre — dont celui qu'AppKit installe pour la barre de format RTF. Rend le NOMBRE d'accessoires effectivement stylés : zéro n'est pas une erreur, cela veut dire qu'il n'y en a aucun à styler pour l'instant.
Function SplitViewHandle() As Ptr
Shared Function SystemIdentifier(symbolName As String) As String
Lit une constante NSToolbarItemIdentifier exportée par AppKit plutôt que d'en deviner la valeur — elles ne suivent pas toutes la même convention. La mécanique vit dans le module Cocoa : elle sert aussi aux types de presse-papiers du glisser-déposer.
Sub ToggleInspector()
Sub ToggleSidebar()
Équivalent programmatique de l'item de toolbar système.
Function AddTopAccessory(area As SplitAreas, view As Ptr) As Ptr
macOS 26. Barre accessoire en haut d'UN volet précis — même famille que l'accessoire de titre que la barre RTF pose sur la fenêtre entière, mais confinée au volet visé. Rend le pointeur du contrôleur créé, à garder pour le retirer ou le masquer.
Function AddBottomAccessory(area As SplitAreas, view As Ptr) As Ptr
Symétrique, sous le contenu du volet.
Sub RemoveAccessory(controller As Ptr)
Passe par removeFromParentViewController, que l'en-tête recommande : inutile de retrouver l'index dans la liste haute ou basse.
Sub SetAccessoryHidden(controller As Ptr, hidden As Boolean)
Réduit l'accessoire à hauteur zéro sans le retirer — réversible sans reconstruire la vue.
Sub SetAllowsOverlay(area As SplitAreas, allow As Boolean)
macOS 26, automaticallyAdjustsSafeAreaInsets. D'autres volets peuvent alors se poser en recouvrement de ce volet, ses safeAreaInsets suivant ce recouvrement.

Propriétés

FullHeightSidebar As Boolean
True : le volet latéral monte derrière la titlebar et la barre d'outils ne commence qu'au diviseur — c'est la disposition des applications système, et la condition pour que NSWindow.title tombe côté détail.
Subtitle As String
Ligne secondaire sous le titre, en gris (macOS 11+). Vide = pas de ligne.
Title As String
Le titre de la FENÊTRE, affiché en gras dans la barre unifiée. Rien à voir avec Label ou Title d'un NativeToolbarItem : c'est cette paire titre/sous-titre que montrent les applications système.
TitleVisible As Boolean
False masque titre ET sous-titre, pour poser une vue personnalisée à la place. C'est ce que faisait la démo — et c'est précisément ce qui empêchait de voir la présentation système.

Événements

  • Event DetailResized(w As Double, h As Double)

Énumérations

SplitAreasSidebar=0Detail=1Inspector=2
ScrollEdgeStylesAutomatic=0SoftEdge=1HardEdge=2
Window

NativeWindowTabs

classe

Les onglets de fenêtre — « Afficher la barre d'onglets », « Fusionner toutes les fenêtres ». Xojo n'en expose rien. Deux conditions, que l'en-tête énonce : tabbingMode « should be set before a window is shown », et deux fenêtres ne se regroupent que si elles partagent le même tabbingIdentifier — vide, AppKit le dérive de la classe de la fenêtre, si bien que deux classes différentes ne se regrouperont jamais.

Méthodes

Shared Sub Configure(w As DesktopWindow, mode As Modes, identifier As String = "")
À appeler AVANT Show. L'identifiant est ce qui autorise deux fenêtres à devenir onglets l'une de l'autre.
Shared Function UserPreference() As Preferences
Le réglage système « Préférer les onglets » : Manual, Always ou InFullScreen. Il décide de ce qu'AppKit fait d'une fenêtre en mode Automatic.
Shared Sub AddTab(host As DesktopWindow, tab As DesktopWindow)
Ajoute une fenêtre comme onglet d'une autre, sans passer par le réglage système.
Shared Sub ToggleTabBar(w As DesktopWindow)
Montre ou masque la barre d'onglets — l'item « Afficher la barre d'onglets » du menu Présentation.
Shared Sub ToggleOverview(w As DesktopWindow)
La vue d'ensemble animée, « Afficher tous les onglets ».
Shared Sub MergeAll(w As DesktopWindow)
Rassemble toutes les fenêtres compatibles en onglets d'une seule.
Shared Sub MoveToNewWindow(w As DesktopWindow)
Détache l'onglet courant dans sa propre fenêtre.
Shared Sub SelectNext(w As DesktopWindow) · SelectPrevious
Navigation d'onglet en onglet.
Shared Function TabCount(w As DesktopWindow) As Integer · TabBarVisible
tabGroup est créé À LA DEMANDE et rendu par une référence FAIBLE : on le relit à chaque appel plutôt que de le retenir.

Énumérations

ModesAutomaticPreferredDisallowed
PreferencesManualAlwaysInFullScreen
Window

NativeWindowStyle

classe

Quatre propriétés de NSWindow que Xojo n'expose pas, et qui font l'essentiel d'un panneau flottant, d'un HUD ou d'une fenêtre épinglée : le niveau d'empilement, l'opacité, le comportement face aux espaces et à Mission Control, et le déplacement à la souris.

Méthodes

Shared Sub SetLevel(w As DesktopWindow, level As Levels)
Le niveau d'empilement. Les valeurs de l'énumération sont MESURÉES, pas recopiées : l'en-tête ne les donne pas en clair, il les définit par kCGNormalWindowLevel et consorts, calculés par CGWindowLevelForKey(). Relevées à l'exécution sur macOS 15.7.9 — Normal 0, Floating 3, ModalPanel 8, MainMenu 24, Status 25, PopUpMenu 101, ScreenSaver 1000.Submenu et TornOffMenu valent 3 eux aussi, soit exactement Floating : ils ne sont pas repris, ils feraient trois noms pour une valeur.
Shared Sub SetLevelRaw(w As DesktopWindow, value As Integer)
Shared Function LevelRaw(w As DesktopWindow) As Integer
En nombre, parce que NSWindowLevel est déclaré NS_TYPED_EXTENSIBLE_ENUM : toute valeur est légitime, et « Floating + 1 » est un idiome courant pour se placer juste au-dessus des palettes.
Shared Sub SetAlpha(w As DesktopWindow, value As Double)
Shared Function Alpha(w As DesktopWindow) As Double
L'opacité de TOUTE la fenêtre, chrome compris, de 0 à 1. La valeur est bornée à cet intervalle : AppKit accepte tout, mais une fenêtre à −3 disparaît sans dire pourquoi.
Shared Sub SetCollectionBehavior(w As DesktopWindow, behaviors() As Behaviors)
Shared Sub SetCollectionBehavior(w As DesktopWindow, behavior As Behaviors)
Le comportement face aux espaces, à Exposé et au plein écran.L'ORDRE COMPTE : l'en-tête précise que le comportement par défaut DÉPEND du niveau — Managed et ParticipatesInCycle si le niveau vaut Normal, Transient et IgnoresCycle sinon. Poser le niveau d'abord. Et « au plus un par groupe » : au plus un parmi Managed/Transient/Stationary, au plus un parmi ParticipatesInCycle/IgnoresCycle, au plus un parmi les trois FullScreen — rien ne le vérifie, ni AppKit ni cette classe.
Shared Function CollectionBehaviorRaw(w As DesktopWindow) As Integer
Shared Function HasBehavior(w As DesktopWindow, behavior As Behaviors) As Boolean
Le masque tel quel, et la façon lisible d'en tester un bit. Default valant zéro, le tester au masque rendrait toujours faux : HasBehavior répond alors à la question telle qu'elle se pose — le masque est-il vide ?
Shared Sub SetMovable(w As DesktopWindow, movable As Boolean)
Shared Function Movable(w As DesktopWindow) As Boolean
macOS 10.6. À faux, le serveur cesse de déplacer la fenêtre par sa barre de titre ou son fond.Deux surprises écrites dans l'en-tête : la fenêtre reste REDIMENSIONNABLE si elle l'était et son cadre reste modifiable par programme ; et le système cesse de la déplacer lors d'un changement de configuration d'écran, ce qui peut la laisser hors champ.
Shared Sub SetMovableByBackground(w As DesktopWindow, value As Boolean)
Shared Function MovableByBackground(w As DesktopWindow) As Boolean
Déplacer la fenêtre en tirant n'importe où dans son fond.Ignoré sans un mot sur une fenêtre non déplaçable — « setMovableByWindowBackground:YES is ignored on a window that returns NO from -isMovable ». Poser Movable à faux puis ceci à vrai ne fait rien du tout.

Sidebar

Deux modèles de données, deux classes, une base commune.

Sidebar

NativeSidebarBase

classe

Base commune extraite une fois que les deux barres existaient. Porte la vibrance, la construction des cellules, les pastilles, la sélection bleue ou grise. Les métriques diffèrent (une vue en arborescence indente) : ce sont des paramètres, pas des constantes.

Méthodes

Sub Refit()
Le style source-list ajoute une marge horizontale AU-DELÀ de la largeur de colonne : la vue devient plus large que sa zone visible et la sélection déborde. À appeler APRÈS la mise en page — sizeLastColumnToFit ne fait rien tant que les dimensions ne sont pas établies.

Propriétés

EmphasizedSelection As Boolean
True : sélection bleue. False : grise, comme une liste sans focus. PAS ReloadList : reloadData DÉSÉLECTIONNE. isEmphasized est interrogé au moment du dessin, un simple redessin suffit donc — et il préserve la sélection.
Width As Double lecture seule
Largeur réelle du volet, lue sur la vue. Lecture seule : c'est le conteneur qui la fixe, pas la barre latérale.
Sidebar

NativeSidebar

classe hérite de NativeSidebarBase

Liste plate sur NSTableView en style source-list. Trois natures de ligne : item, séparateur, en-tête de section — les en-têtes ne sont pas sélectionnables et PageForRow les ignore.

Constructeur

Sub Constructor()

Méthodes

Sub Add(title As String, sfSymbol As String)
Sub Add(title As String, sfSymbol As String, iconColor As Color)
Sub AddSection(title As String)
En-tête de section : petites capitales grises, non sélectionnable. Genre 2 dans mKinds — 0 = item, 1 = séparateur, 2 = en-tête.
Sub AddSeparator()
Function BuildSidebarView(width As Double, height As Double, topInset As Double = 0) As Ptr
Construit la vue de barre latérale SEULE — vibrance + table source-list + footer. Ni NSSplitView, ni styleMask, ni contentView : le conteneur est l'affaire de l'appelant — NativeWindowChrome monte cette vue dans un NSSplitViewItem.
Function Count() As Integer
Sub Insert(index As Integer, title As String, sfSymbol As String)
Function PageForTitle(title As String) As Integer
Viser une page par son INTITULÉ plutôt que par un numéro : un appelant qui code « page 15 » en dur se trompe dès qu'on insère une entrée au-dessus.La comparaison est faite avec « = », et c'est délibéré : en Xojo l'égalité de deux String ignore la CASSE — la même insensibilité qui fait que « isa » EST l'opérateur IsA. Pour comparer strictement, il faudrait StrComp(a, b, 1).
Function RowForPage(page As Integer) As Integer
L'inverse exact de PageForRow.
Function SelectPage(page As Integer) As Boolean
VÉRIFIÉ plutôt que supposé : selectRowIndexes:byExtendingSelection: prévient BIEN le délégué — tableViewSelectionDidChange: part comme sur un clic. Une application qui écoute SelectionChanged voit donc arriver la page toute seule ; inutile de la lui pousser une seconde fois.Sauf lorsque la ligne est DÉJÀ sélectionnée : AppKit ne notifie pas une sélection inchangée. C'est correct — rien n'a bougé —, mais un appelant qui compterait sur l'événement pour se synchroniser doit le savoir.
Function PageForRow(row As Integer) As Integer
Rang de la ligne parmi les lignes SÉLECTIONNABLES, séparateurs exclus. Évite à l'appelant de coder en dur la position des séparateurs — arithmétique qui casse dès qu'on en ajoute un.
Sub Remove(index As Integer)
Sub SetBadge(index As Integer, text As String)
Compteur en pastille sur une entrée, façon Mail. Chaîne vide = pas de pastille.
Sub SetFooter(title As String, sfSymbol As String)
Row spécial épinglé EN BAS (séparateur + icône/label cliquable). À appeler AVANT BuildSidebarView. Le clic émet l'event FooterClicked.

Propriétés

SelectedIndex As Integer

Événements

  • Event FooterClicked()
  • Event SelectionChanged(index As Integer)
Sidebar

NativeOutlineSidebar

classe hérite de NativeSidebarBase

Hiérarchie sur NSOutlineView, sections repliables. Chaque ligne est représentée par une NSString retenue et mise en cache : la vue retient et compare ces pointeurs, il faut donc que le même revienne pour la même ligne.

Constructeur

Sub Constructor()

Méthodes

Function AddSection(title As String) As Integer
Renvoie l'index de la section, à passer ensuite à AddItem.
Sub AddItem(section As Integer, title As String, sfSymbol As String = "", iconColor As Color = &c8E8E93)
Function BuildSidebarView(width As Double, height As Double) As Ptr
Barre latérale hiérarchique : NSOutlineView en style source-list, dans une NSScrollView, sur une NSVisualEffectView. Les sections sont des « group rows » repliables ; le triangle apparaît au survol, comme dans le Finder.
Sub CollapseAll()
Sub ExpandAll()
Function ItemCount(section As Integer) As Integer
Sub SetBadge(section As Integer, item As Integer, text As String)
Compteur en pastille sur une entrée. Chaîne vide = pas de pastille.
Function SectionCount() As Integer

Propriétés

SelectedPage As Integer lecture seule
Rang de la ligne sélectionnée parmi TOUS les items, sections exclues : l'appelant retrouve ainsi un index de page comme avec NativeSidebar.

Événements

  • Event SelectionChanged(page As Integer)

Toolbar

NSToolbar et ses types d'items, sans une ligne d'Objective-C compilé.

Toolbar

NativeToolbar

classe

La NSToolbar et son delegate. Tous les items doivent être ajoutés avant Attach : setToolbar: est le moment où AppKit demande la liste par défaut.

Constructeur

Sub Constructor(identifier As String)

Méthodes

Sub AddItem(item As NativeToolbarItem)
Le jeu PAR DÉFAUT : ce que la barre montre tant que l'utilisateur n'a rien personnalisé, et la rangée du bas de la feuille de personnalisation.
Sub AddAvailableItem(item As NativeToolbarItem)
Le CATALOGUE : l'item est proposé dans la feuille de personnalisation sans être posé dans la barre. AppKit ne sait fabriquer que ce que le delegate annonce dans toolbarAllowedItemIdentifiers:, d'où l'enregistrement ici.
Sub Attach(w As DesktopWindow)
Sub Attach(windowHandle As Ptr)
Tous les items doivent avoir été ajoutés AVANT : c'est au moment du setToolbar: qu'AppKit interroge toolbarDefaultItemIdentifiers: pour peupler la barre.
Sub SetItemIdentifiers(identifiers() As String)
macOS 15. Pose le CONTENU de la barre en une affectation, AppKit faisant le diff — insertions et retraits animés, sans reconstruire. L'en-tête met en garde : « will override any customizations the user has made ». Sur une barre personnalisable et autosauvée, cet appel efface l'agencement de l'utilisateur.
Function ItemIdentifiers() As String()
Ce que la barre montre EN CE MOMENT, personnalisation comprise — à la différence du jeu par défaut, qui ne bouge pas.
Sub RemoveItem(identifier As String)
macOS 15. Retire UN item par son identifiant, là où RemoveAll est tout ou rien. Deux précisions de l'en-tête : si plusieurs items partagent l'identifiant, c'est le PREMIER qui part, et le changement se propage immédiatement à toutes les barres de même identifiant. L'item quitte la barre, pas le catalogue — il reste donc proposé dans la palette.
Sub RemoveAll()
Vide la barre. Utile pour la reconstruire dans un autre style — les groupes d'items, par exemple, sont refusés par le style Preference.
Sub ResetConfiguration()
Efface la personnalisation enregistrée et remet le jeu par défaut. AppKit n'expose rien pour cela : la configuration est écrite dans les préférences sous « NSToolbar Configuration <identifiant> », et la retirer ne suffit pas — la barre vivante garde ses items, il faut les reposer.
Sub RunCustomizationPalette()
Ouvre la palette de personnalisation ; exige AllowsUserCustomization = True.
Function Handle() As Ptr
Function Item(identifier As String) As NativeToolbarItem
Sub ValidateVisibleItems()

Propriétés

AllowsDisplayModeCustomization As Boolean
macOS 15. La partie « Icône et texte / Icône seule / Texte seul » du menu contextuel et de la feuille. INDÉPENDANTE de AllowsUserCustomization, qui ne gouverne que l'ordre des items. Défaut YES pour une application liée sur macOS 15 — donc active sans qu'on l'ait demandée.
AllowsUserCustomization As Boolean
AutosavesConfiguration As Boolean
À True, AppKit écrit lui-même dans les préférences ce que l'utilisateur change — ordre des items, items retirés, mode d'affichage — et le relit à la construction suivante d'une barre de même identifiant. À poser AVANT Attach : c'est au setToolbar: que la configuration est relue. Défaut False.
DisplayMode As DisplayModes
Visible As Boolean
Style As ToolbarStyles
Applicable avant ou après Attach : ApplyStyle est rejoué à l'attache.

Événements

  • Event ItemPressed(item As NativeToolbarItem)

Énumérations

DisplayModesDefaultIconAndLabelIconOnlyLabelOnly
ToolbarStylesAutomaticExpandedPreferenceUnifiedUnifiedCompact
Toolbar

NativeToolbarItem

classe

Un NSToolbarItem. Le constructeur prend un nom de classe Objective-C optionnel, ce qui permet aux sous-classes d'instancier la leur en héritant de tout le reste.

Constructeur

Sub Constructor(identifier As String, objcClassName As String = "NSToolbarItem")

Méthodes

Shared Function FlexibleSpaceItem() As NativeToolbarItem
Identifiant système : AppKit fabrique l'item lui-même, le delegate renvoie Nil.
Shared Function ContainerItem(identifier As String, container As DesktopContainer) As NativeToolbarItem
Item dont la vue est celle d'un DesktopContainer. Si le container implémente ToolbarItemContainer, son SetEnabled est appelé à chaque changement d'état : AppKit ne sait pas griser les contrôles d'une vue personnalisée.
Shared Function SystemItem(identifier As String) As NativeToolbarItem
Identifiant fourni par AppKit (toggle de sidebar, césure automatique, espaces) : le delegate renvoie Nil et AppKit fabrique puis pilote l'item lui-même.
Sub WireSubItems(target As Ptr, action As Ptr)
Sans effet pour un item simple ; NativeToolbarItemGroup la surcharge.
Function SubItems() As NativeToolbarItem()
Vide pour un item simple ; NativeToolbarItemGroup la surcharge.
Function Handle() As Ptr
Le NSToolbarItem sous-jacent. Nil pour les identifiants système (espaces).
Function IsSystemItem() As Boolean
Function ItemIdentifier() As String
Function RespondsToClicks() As Boolean
False pour les espaces et le séparateur de suivi : pas de target/action dessus.
Sub ClearBadge()
Function BadgeSupported() As Boolean
macOS 26+. Permet à l'appelant d'adapter son interface plutôt que de proposer un réglage sans effet.
Sub SetBadge(count As Integer)
Pastille numérotée (macOS 26+).
Sub SetBadge(text As String)
Pastille textuelle, ou simple point si le texte est vide (macOS 26+).
Sub SetIcon(sfSymbolName As String, accessibilityDescription As String = "")
Sub SetView(view As Ptr)
Vue personnalisée (champ de titre, contrôle sur mesure…).L'item cesse alors de réclamer target/action à la barre : quand la vue est un NSControl, AppKit répercute le target/action de l'item DESSUS et écrase la cible propre du contrôle — son événement ne part alors plus jamais. Une vue personnalisée gère son interaction elle-même.
Shared Function SpaceItem() As NativeToolbarItem
Shared Function TrackingSeparatorToolbarItem(identifier As String, splitView As Ptr, dividerIndex As Integer) As NativeToolbarItem
Césure de toolbar alignée sur un diviseur de NSSplitView (macOS 11+).

Propriétés

AutoValidates As Boolean
False = l'état Enabled posé à la main fait foi, AppKit ne revalide pas. True (défaut AppKit) = validateToolbarItem: est interrogé périodiquement ; NativeToolbar y répond en renvoyant Enabled, donc le résultat est le même.
IsHidden As Boolean
Navigational As Boolean
Place l'item dans la zone de navigation, à gauche (macOS 11+).
VisibilityPriority As Integer
Plus la valeur est haute, plus l'item résiste au rétrécissement de la barre.
Bordered As Boolean
Enabled As Boolean
Title As String
Texte AFFICHÉ DANS le bouton, à côté ou à la place de l'icône (macOS 10.15+). À ne pas confondre avec Label, qui est la légende SOUS l'item.
BackgroundTintColor As Color
macOS 26+. Ignoré silencieusement en dessous : on interroge le sélecteur plutôt que le numéro de version — présent ou absent, c'est un fait.
Style As ItemStyles
macOS 26+ : Plain, ou Prominent pour un item mis en avant façon « Terminé ».
Label As String
ToolTip As String

Énumérations

ItemStylesPlainProminent
Toolbar

NativeToolbarItemGroup

classe hérite de NativeToolbarItem

Groupe d'items, rendu en segments ou en menu déroulant selon ControlRepresentations.

Constructeur

Sub Constructor(identifier As String)

Méthodes

Sub AddItem(item As NativeToolbarItem)
Les sous-items sont retenus côté Xojo : setSubitems: ne garantit pas la survie de nos wrappers, seulement celle des objets ObjC.
Sub WireSubItems(target As Ptr, action As Ptr)
AppKit route le clic d'un groupe vers ses SOUS-ITEMS : sans target/action sur eux, le groupe est inerte. Mais leur en poser une fois qu'ils appartiennent déjà au groupe termine le processus à la première mise en page — reproduit deux fois.Hypothèse testée ici : le groupe copie ses sous-items à l'assemblage, et former une référence faible (NSToolbarItem.target l'est) vers une instance de classe créée au runtime pendant cette copie est ce qui casse. On câble donc pendant qu'ils n'appartiennent à personne, puis on réassemble.
Function SubItems() As NativeToolbarItem()
Accesseur : les sous-items appartiennent au groupe, pas à la barre. Ne JAMAIS leur écrire target/action — c'est ce qui faisait planter AppKit à la première mise en page.

Propriétés

ControlRepresentation As ControlRepresentations
Collapsed = un seul bouton qui déroule un menu ; Expanded = tous visibles.
SelectedIndex As Integer
SelectionMode As SelectionModes

Énumérations

ControlRepresentationsAutomaticExpandedCollapsed
SelectionModesSelectOneSelectAnyMomentary
Toolbar

NativeMenuToolbarItem

classe hérite de NativeToolbarItem

NSMenuToolbarItem : un item qui déroule un menu.

Constructeur

Sub Constructor(identifier As String)

Méthodes

Sub AddMenuItem(title As String, tag As Integer = -1)
Ajoute une entrée au menu déroulant. Le tag remonte dans l'event MenuItemSelected ; s'il est omis, c'est le rang de l'entrée qui est utilisé.
Sub AddSeparator()

Propriétés

ShowsIndicator As Boolean
False = le bouton n'affiche pas le chevron du menu.

Événements

  • Event MenuItemSelected(title As String, tag As Integer)
Toolbar

NativeSearchToolbarItem

classe hérite de NativeToolbarItem

NSSearchToolbarItem : le champ de recherche qui s'étend et se rétracte selon la place disponible.

Constructeur

Sub Constructor(identifier As String)

Méthodes

Sub BeginSearchInteraction()
Déplie le champ et lui donne le focus.
Function SearchFieldHandle() As Ptr
Le NSSearchField hébergé par l'item.

Propriétés

PlaceholderText As String
PreferredWidth As Double
Text As String

Événements

  • Event SearchEnded()
  • Event SearchStarted()
  • Event TextChanged(text As String)
Toolbar

NativeSharingToolbarItem

classe hérite de NativeToolbarItem

NSSharingServicePickerToolbarItem : le bouton de partage système.

Constructeur

Sub Constructor(identifier As String)

Méthodes

Sub SetFiles(paths() As String)
Les fichiers proposés au partage. Copiés côté Xojo, relus à chaque clic.
Toolbar

ToolbarItemContainer

interface

Interface à faire porter par un DesktopContainer employé comme vue d'item : AppKit ne sait pas propager l'activation à une vue personnalisée, c'est au container de le faire.

Méthodes

Sub SetEnabled(enabled As Boolean)
Appelée quand l'item de toolbar qui héberge ce container change d'état : au container de propager activation ou grisage à ses propres contrôles, AppKit ne sachant pas le faire pour une vue personnalisée.

Controls

Un contrôle AppKit par classe, posé dans un DesktopCanvas servant d'ancre — ou dans la vue d'un item de barre d'outils.

Controls

NativeButton

classe

NSButton et tout le nuancier de bezelStyle : le rond d'aide, le triangle de repli, la pastille de compteur, la capsule de barre d'accessoires.

Constructeur

Sub Constructor(title As String, style As BezelStyles = BezelStyles.Push)

Méthodes

Function Handle() As Ptr
Sub Refit()
À rappeler après avoir changé le titre, le style ou le symbole : la taille idéale d'un bouton dépend de son bezel autant que de son contenu.
Sub SetButtonType(type_ As ButtonTypes)
Le TYPE décide du comportement au clic — impulsion, bascule, case, radio — là où le bezel ne décide que du dessin. Les deux sont indépendants : une case à cocher garde un bezel, un bouton poussoir peut se comporter en bascule. Le constructeur pose MomentaryPushIn, le bouton ordinaire.Attention : setButtonType: REMET le bezel et l'image à des valeurs propres au type. À appeler AVANT de régler BezelStyle, jamais après.
Sub SetBordered(bordered As Boolean)
Sans bordure, un bouton à symbole devient une simple icône cliquable : c'est ce qu'il faut dans une barre de commandes qui porte déjà son fond.
Sub SetControlSize(size As ControlSizes)
Shared Function FontSizeForControlSize(size As ControlSizes) As Double
La taille de police que le système associe à ce gabarit — mesuré sur macOS 15.7.9 : Regular 13, Small 11, Mini 9, Large 13. AppKit ne relie PAS les deux propriétés : setControlSize: n'agit que sur les métriques et ne change jamais la police d'un contrôle. Pour qu'un libellé suive le gabarit, poser soi-même FontSize avec cette valeur.Large est identique à Regular. ExtraLarge rend 12 sur un système antérieur à macOS 26 : valeur de repli sans signification, à ne pas employer avant vérification sur le SDK 26.
Sub SetDefault(isDefault As Boolean)
Le bouton par défaut n'est pas un style : c'est celui qui répond à Retour. AppKit le teinte alors de la couleur d'accentuation, de lui-même.
Sub SetDestructive(destructive As Boolean)
macOS 11+. Le bouton passe en rouge, comme « Supprimer » dans une alerte. Sur un système antérieur, l'appel est simplement sans effet.
Sub SetSymbol(symbolName As String, accessibilityDescription As String = "")
Symbole SF plutôt qu'un titre — indispensable pour les bezels ronds (Circular) où un mot ne tiendrait pas.
Sub SetImage(item As FolderItem)
Une image du DISQUE, quand le sujet n'existe pas en symbole — un logo d'application, par exemple.
Sub SetPicture(source As Picture)
Une Picture Xojo, pour ce qui est dessiné dans l'application. CopyOSHandle rend un NSImage dont on devient PROPRIÉTAIRE — « Copy » dans le nom — et le bouton le retient de son côté : il est relâché après avoir été posé.

Propriétés

ImagePosition As ImagePositions
Où l'icône se place par rapport au titre. NSCellImagePosition, relevé dans NSCell.h — les valeurs ne suivent aucun ordre visuel : Below vaut 4 et Above 5. Leading et Trailing suivent le sens d'écriture ; Left et Right ne bougent jamais.MESURÉ : fittingSize IGNORE Above et Below — il rend la même hauteur que sans image, 24 points. La hauteur est donc à poser soi-même.
ImageHugsTitle As Boolean
À True, l'icône se colle au titre et l'ensemble se centre — c'est presque toujours ce qu'on veut. À False, elle se plaque contre le bord du cadre et le titre se centre dans ce qui reste : l'icône paraît alors abandonnée à l'écart du mot.
BezelStyle As BezelStyles
State As Integer
NSControlStateValue : Off = 0, On = 1, Mixed = -1. N'a de sens qu'avec un type à état — Switch, Radio, PushOnPushOff, OnOff.
Enabled As Boolean
Title As String
BorderShape As NativeControlHost.BorderShapes
macOS 26. Le SÉLECTEUR est interrogé, pas le numéro de version : sur un système antérieur le contrôle garde son aspect au lieu de lever.
TintProminence As NativeControlHost.TintProminences
macOS 26. Le SÉLECTEUR est interrogé, pas le numéro de version : sur un système antérieur le contrôle garde son aspect au lieu de lever.

Événements

  • Event Pressed()

Énumérations

BezelStylesAutomatic=0Push=1FlexiblePush=2Disclosure=5ShadowlessSquare=6Circular=7TexturedSquare=8HelpButton=9SmallSquare=10Toolbar=11AccessoryBarAction=12AccessoryBar=13PushDisclosure=14Badge=15Glass=16
ButtonTypesMomentaryLight=0PushOnPushOff=1Toggle=2Switch=3Radio=4MomentaryChange=5OnOff=6MomentaryPushIn=7Accelerator=8MultiLevelAccelerator=9
ControlSizesRegular=0Small=1Mini=2Large=3ExtraLarge=4
Controls

NativeComboButton

classe

NSComboButton (macOS 13+) : une action principale et un menu. Les éléments du menu portent leur propre cible et action, indépendantes de l'action principale.

Constructeur

Sub Constructor(title As String, style As Styles = Styles.Split)

En style Split, la flèche est une zone à part : cliquer le titre déclenche l'action, cliquer la flèche ouvre le menu. En Unified, un seul segment : l'action étant posée, le clic la déclenche et le menu n'apparaît qu'à l'appui maintenu — l'en-tête le dit, et cette classe pose toujours son action.

Méthodes

Function Handle() As Ptr
Sub AddItem(title As String)
L'en-tête est explicite : les éléments du menu portent LEUR PROPRE cible et action, indépendantes de l'action principale du bouton. Le tag transporte l'indice, seul moyen de savoir lequel a été choisi.
Sub RemoveAllItems()
Function ItemCount() As Integer
Vide le menu et remet le compteur à zéro : le tag de chaque élément est son rang, et les éléments ajoutés ensuite porteraient sinon des indices décalés.
Sub SetItems(ParamArray titles() As String)
Sub SetSymbol(symbolName As String, accessibilityDescription As String = "")

Propriétés

Style As Styles
Title As String

Événements

  • Event ItemChosen(index As Integer, title As String)
  • Event Pressed()

Énumérations

StylesSplit=0Unified=1
Controls

NativePopupButton

classe

NSPopUpButton, surgissant (la sélection s'affiche) ou déroulant (le premier élément sert de titre fixe, comme un bouton « Action »).

Constructeur

Sub Constructor(pullsDown As Boolean = False, style As NativeButton.BezelStyles = NativeButton.BezelStyles.Push)

Méthodes

Function Handle() As Ptr
Sub AddItem(title As String)
Sub AddSeparator()
Function Count() As Integer
Sub RemoveAllItems()
Sub SetItems(ParamArray titles() As String)
UsesItemFromMenu As Boolean
macOS 15. En DÉROULANT, YES fait servir le premier item de titre et le masque de la liste ; NO laisse le bouton porter son propre titre, vide tant qu'on n'en a pas posé. Le setter appelle synchronizeTitleAndSelectedItem : AppKit ne re-dérive PAS le titre en repassant à YES, et sans cela décocher puis recocher laisse le bouton définitivement muet.
AltersStateOfSelectedItem As Boolean
macOS 15. YES coche l'item choisi. « This property is ignored for pull-down buttons » : un déroulant n'a pas d'item sélectionné à cocher.

Propriétés

BezelStyle As NativeButton.BezelStyles
SelectedIndex As Integer
SelectedTitle As String lecture seule

Événements

  • Event Changed(index As Integer)
Controls

NativeSwitch

classe

NSSwitch (10.15+). Contrairement à un interrupteur redessiné à la main, il suit le mode sombre, la couleur d'accentuation et l'animation du système sans qu'on s'en occupe.

Constructeur

Sub Constructor(onState As Boolean = False)

Méthodes

Function Handle() As Ptr

Propriétés

Value As Boolean
NSControlStateValue : Off = 0, On = 1 (Mixed = -1, sans objet ici).

Événements

  • Event Changed(value As Boolean)
Controls

NativeStepper

classe

NSStepper — les deux petites flèches. Xojo a DesktopUpDownArrows, mais sans pas réglable, sans bouclage ni répétition automatique.

Constructeur

Sub Constructor(minimum As Double = 0, maximum As Double = 100, increment As Double = 1, value As Double = 0)

Méthodes

Function Handle() As Ptr
Sub SetBehaviour(autorepeat As Boolean, wraps As Boolean)
autorepeat : maintenir la flèche fait défiler les valeurs. wraps : passé le maximum, on repart du minimum — utile pour des heures.

Propriétés

Value As Double

Événements

  • Event Changed(value As Double)
Controls

NativeTextField

classe

NSTextField. Deux bezels seulement, carré et arrondi ; le troisième cas utile, le champ « à plat », s'obtient par SetBordered(False, False).

Constructeur

Sub Constructor(placeholder As String = "", style As Bezels = Bezels.Square)

Méthodes

Function Handle() As Ptr
Sub SetAlignment(alignment As Alignments)
NSTextAlignment ne vaut pas les mêmes nombres selon l'architecture : le SDK bascule sur TARGET_ABI_USES_IOS_VALUES. Sur Apple Silicon, Centre = 1 et Droite = 2 ; sur Intel, l'inverse.
Sub SetBordered(bordered As Boolean, drawsBackground As Boolean = True)
Sub SetEditable(editable As Boolean, selectable As Boolean = True)
Sub SetPlaceholders(ParamArray items() As String)
macOS 26 : PLUSIEURS invites, que le champ fait défiler l'une après l'autre — « Rechercher un paquet », puis « Rechercher un composant »…Le repli n'est pas « ne rien faire » : sur un système antérieur on pose la PREMIÈRE. Un champ qui perdrait toute invite serait une régression, pas une dégradation.
AllowsWritingTools As Boolean
macOS 15.2, défaut YES. À mettre à NO pour un champ qui ne contient pas de la prose : un identifiant, un chemin, une clé de licence.
AllowsWritingToolsAffordance As Boolean
macOS 15.4, défaut NO. Le bouton que le système pose dans le champ. Ne vaut que si le précédent est vrai.
Sub SetContentType(kind As ContentTypes)
NSTextContentType — un indice sémantique sur ce que le champ ATTEND, pas un accès à quoi que ce soit. C'est lui qui permet au système de proposer, au-dessus du champ, le code à usage unique reçu par SMS ou iMessage : l'app ne lit jamais le message, seul le système y a accès. Les valeurs Téléphone, E-mail, URL n'ont pas d'effet visible sans donnée déjà connue du système — c'est un indice, pas un rendu.
Shared Function SymbolFor(kind As ContentTypes) As String
Nom du symbole AppKit exporté pour une valeur donnée. Publique et partagée : NativeTextFieldControl s'en sert aussi, plutôt que de recopier les 43 cas.

Propriétés

Bezel As Bezels
setBezelStyle: n'a d'effet que sur un champ bordé : sans bordure il n'y a pas de bezel à dessiner.Sous macOS 27, Square et Rounded se dessinent à l'identique — mêmes coins arrondis, même filet d'environ 12 % de gris, mesuré au pixel sur un système 27.0. Le réglage reste posé et garde son sens sous macOS 15. Voir le piège « un champ blanc sur une fenêtre blanche ».
Placeholder As String
Text As String

Événements

  • Event Accepted(text As String)
  • Event Changed(text As String)

Énumérations

ContentTypesNone=0Username=1Password=2OneTimeCode=3NewPassword=4Name=5TelephoneNumber=24EmailAddress=25URL=26BirthdateYear=43
AlignmentsLeading=0Center=1Trailing=2
BezelsSquare=0Rounded=1
Controls

NativeComboBox

classe

NSComboBox en mode liste interne. Ce n'est pas un NSPopUpButton : le champ reste éditable, donc SelectedIndex vaut −1 dès que la saisie sort de la liste — c'est normal.

Constructeur

Sub Constructor(placeholder As String = "")

On reste en mode « liste interne » (usesDataSource = NO) : les éléments vivent dans le contrôle, sans dataSource à tenir.

Méthodes

Function Handle() As Ptr
Sub AddItem(value As String)
Function Count() As Integer
Sub RemoveAllItems()
Sub SetCompletes(completes As Boolean)
La saisie se complète toute seule sur le premier élément qui commence pareil, comme le champ d'adresse de Mail.
Sub SetItems(ParamArray values() As String)
Sub SetVisibleItems(count As Integer)
Nombre de lignes montrées avant que la liste ne défile. 5 par défaut.

Propriétés

Placeholder As String
SelectedIndex As Integer
-1 quand le texte saisi ne correspond à aucun élément — le cas normal d'une combo, qui accepte les valeurs libres.
Text As String

Événements

  • Event Accepted(text As String)
  • Event Changed(text As String)
  • Event SelectionChanged(index As Integer, value As String)
Controls

NativeSearchField

classe

NSSearchField : la loupe, la croix d'effacement, le menu des recherches récentes et le comportement au clavier viennent avec.

Constructeur

Sub Constructor(placeholder As String = "")

Méthodes

Function Handle() As Ptr
Function RecentSearches() As String()
Sub SetLiveSearch(live As Boolean)
Par défaut l'action ne part qu'à la validation. En mode direct, elle part à chaque frappe — pratique pour filtrer une liste au fil de la saisie.
Sub SetRecentsMenu(maximumRecents As Integer = 10)
Sans menu gabarit, la loupe reste muette. AppKit remplace lui-même les éléments marqués par un tag spécial ; on se contente de fournir le moule.
Sub SetPlaceholders(ParamArray items() As String)
macOS 26 : PLUSIEURS invites, que le champ fait défiler l'une après l'autre — « Rechercher un paquet », puis « Rechercher un composant »…Le repli n'est pas « ne rien faire » : sur un système antérieur on pose la PREMIÈRE. Un champ qui perdrait toute invite serait une régression, pas une dégradation.

Propriétés

Placeholder As String
Text As String

Événements

  • Event Changed(text As String)
Controls

NativeLevelIndicator

classe

NSLevelIndicator : jauge de capacité, indicateur de pertinence ou étoiles de notation. AppKit ne connaît que deux seuils, et seulement dans le sens « au-dessus = mauvais » ; tout autre sens passe par SetBands.

Constructeur

Sub Constructor(style As Styles = Styles.DiscreteCapacity, minimum As Double = 0, maximum As Double = 10, value As Double = 5)

Méthodes

Function Handle() As Ptr
Sub SetEditable(editable As Boolean)
Rend la jauge manipulable à la souris — indispensable pour une notation.
Sub SetBands(thresholds() As Double, colors() As Color)
Généralise SetThresholds à un nombre quelconque de bandes.thresholds doit être croissant, et colors compter un élément de plus : la valeur prend colors(i) dès qu'elle est <= thresholds(i), la dernière couleur couvrant tout ce qui dépasse le dernier seuil. Le sens de lecture ne tient donc qu'à l'ordre des couleurs — rouge en tête pour une jauge de batterie, vert en tête pour un remplissage de disque. SetBands(Array(2.0, 4.0, 7.0), Array(rouge, orange, jaune, vert))
Sub SetThresholds(warning As Double, critical As Double, inverted As Boolean = False)
Deux sémantiques, et une seule est native.NORMALE (inverted = False) : AU-DESSUS du seuil d'alerte la jauge passe en jaune, au-dessus du seuil critique en rouge. C'est le comportement d'AppKit, documenté ainsi dans l'en-tête — « values above the warning threshold ». Convient à un remplissage de disque : plus c'est haut, plus c'est mauvais. INVERSÉE (inverted = True) : EN DESSOUS du seuil d'alerte jaune, en dessous du critique rouge — le sens d'une jauge de batterie. AppKit ne sait pas le faire, alors ce n'est qu'un cas particulier de SetBands à trois bandes.
Sub SetTicks(count As Integer, major As Integer = 0)

Propriétés

Value As Double

Événements

  • Event Changed(value As Double)

Énumérations

StylesRelevancyContinuousCapacityDiscreteCapacityRating
Controls

NativeColorWell

classe

NSColorWell et, depuis macOS 13, ses trois présentations — dont deux qui ouvrent un sélecteur en popover au lieu du grand panneau système.

Constructeur

Sub Constructor(initialColor As Color = &c007AFF, style As Styles = Styles.Standard)

Méthodes

Function Handle() As Ptr

Propriétés

Style As Styles
colorWellStyle date de macOS 13 ; en dessous, le puits garde la présentation classique sans qu'on ait à s'en soucier.
Value As Color
MaximumLinearExposure As Double
macOS 26. Le SÉLECTEUR est interrogé, pas le numéro de version : sur un système antérieur le contrôle garde son aspect au lieu de lever. Au-delà de 1, le puits laisse choisir des couleurs HDR : la valeur est l'exposition linéaire maximale acceptée.

Événements

  • Event Changed(value As Color)

Énumérations

StylesStandard=0Minimal=1Expanded=2
Controls

NativeColorSampler

classe

NSColorSampler (10.15+) : la pipette système, celle qui grossit le pixel sous le curseur. Sa seule méthode prend un bloc Objective-C.

Constructeur

Sub Constructor()

Sa seule méthode prend un BLOC Objective-C. Xojo en fabrique un depuis 2019r2 avec la classe ObjCBlock du framework : on lui donne un Delegate, elle rend un Handle à passer au Declare. Rien à monter en mémoire.

Méthodes

Function Handle() As Ptr
Function Show() As Boolean
Rend False si la pipette n'est pas disponible — système trop ancien. Le prélèvement est ASYNCHRONE : Show revient tout de suite, l'événement Picked arrive plus tard. L'instance doit donc survivre jusque-là, dans une propriété de la fenêtre.

Événements

  • Event Picked(value As Color, cancelled As Boolean)

Delegate

  • Delegate Sub SamplerHandler(nsColor As Ptr)
Controls

NativeDatePicker

classe

NSDatePicker. Xojo a bien un DesktopDatePicker, mais pas le style ClockAndCalendar — le vrai calendrier avec son horloge — ni le mode plage, ni le choix fin des éléments affichés.

Constructeur

Sub Constructor(style As Styles = Styles.TextFieldAndStepper)

Méthodes

Function Handle() As Ptr
Sub SetBordered(bezeled As Boolean, bordered As Boolean = False)
Sub SetElements(dateElements As DateElements, timeElements As TimeElements)
NSDatePickerElementFlags est un CHAMP DE BITS, pas une énumération simple : les deux groupes se combinent. YearMonthDay vaut 224 et contient déjà YearMonth (192) ; HourMinuteSecond (14) contient HourMinute (12).
Sub SetRange(minimum As DateTime, maximum As DateTime)
Passer Nil des deux côtés retire les bornes.

Propriétés

Duration As Double
En mode Range, la durée en secondes couverte à partir de Value ; 0 en mode OneDate.
Mode As Modes
Style As Styles
Value As DateTime

Événements

  • Event Changed(value As DateTime, duration As Double)

Énumérations

DateElementsNone=0YearMonth=192YearMonthDay=224
ModesOneDate=0DateRange=1
StylesTextFieldAndStepper=0ClockAndCalendar=1TextField=2
TimeElementsNone=0HourMinute=12HourMinuteSecond=14
Controls

NativeOutlineView

classe hérite de NativeTableView

Une arborescence à colonnes — le tableau hiérarchique du Finder en mode liste. AppKit fait dériver NSOutlineView de NSTableView : cette classe hérite donc de NativeTableView et n'ajoute que la hiérarchie — cases à cocher, menus, cellules éditables, jauges, couleurs, alignements et en-tête viennent de la classe de base. Un nœud est un objet, NativeOutlineNode, dont le numéro ne change jamais : il reste valable quoi qu'on insère, retire ou déplace ailleurs, et c'est ce qui permet à l'insertion, à la suppression et au déplacement de s'animer. AddFolder peuple depuis le disque sans entrer dans les paquets. Le tri est refusé : l'ordre du stockage est l'ordre des frères. NativeOutlineSidebar enveloppe le même NSOutlineView pour une liste source : deux niveaux, une colonne, sans en-tête.

Constructeur

Sub Constructor(width As Double = 600, height As Double = 300)

Le modèle, depuis le 14 septembre 2026. L'arbre tient les nœuds dans l'ordre du stockage, leurs parents (Nil pour la racine) et une table numéro → ligne refaite après chaque changement de structure. Les clés remises à AppKit sont liées au numéro du nœud, jamais à sa ligne : elles restent justes quoi qu'on déplace. L'ancien modèle rendait l'indice de ligne comme identifiant, et seul l'ajout pouvait s'animer.

Construire

Function AddNode(parent As NativeOutlineNode, ParamArray cells() As String) As NativeOutlineNode
Function AddNodeArray(parent As NativeOutlineNode, cells() As String) As NativeOutlineNode
Ajoute un nœud en dernier enfant de parentNil pour la racine — et le rend : c'est lui qu'on garde, et qu'on passe comme parent de ses enfants.Sans animation : la forme qui sert à bâtir un arbre avant de l'afficher. AddNodeArray est publique parce qu'un ParamArray ne se transmet pas d'une méthode à l'autre. Et AddRow, hérité du tableau, crée désormais un nœud de premier niveau au lieu d'agrandir le stockage sans nœud.
Function AddFolder(parent As NativeOutlineNode, item As FolderItem, depth As Integer = 3) As NativeOutlineNode
Peuple l'arbre depuis le disque. Le genre vient de NativeFileKind : une application ou une bibliothèque Photos est un dossier pour le système de fichiers, mais on n'entre pas dedans — le Finder non plus.Écrit trois colonnes : nom, genre, taille. Les suivantes restent vides — c'est là qu'on met une case à cocher pour composer une charge utile.

Modifier, animé

Function InsertNode(parent As NativeOutlineNode, index As Integer, cells() As String, animation As NativeTableView.Animations = SlideDown) As NativeOutlineNode
Function AddNodeAnimated(parent As NativeOutlineNode, cells() As String, animation As NativeTableView.Animations = FadeSlideDown) As NativeOutlineNode
Insère un nœud à la position index parmi les enfants de parent ; hors bornes, en dernier. AddNodeAnimated est la même en dernière position.Le stockage suit l'ordre des frères : la ligne est rangée juste avant celle du frère qu'elle précède. L'indice remis à AppKit est la position finale — la sémantique d'insertObjects:atIndexes:, que l'en-tête reprend.
Sub RemoveNode(node As NativeOutlineNode, animation As NativeTableView.Animations = SlideUp)
Retire le nœud et toute sa descendance. Les autres nœuds gardent leur numéro ; seuls les retirés deviennent invalides, et chaque méthode les ignore alors sans lever.
Function MoveNode(node As NativeOutlineNode, newParent As NativeOutlineNode, index As Integer) As Boolean
Déplace le nœud avec sa descendance à la position index parmi les enfants de newParent — position finale, comptée sans le nœud. Rend False, sans rien faire, pour un déplacement dans sa propre descendance.Prouvé avant d'être écrit : 180 000 opérations aléatoires — insertions, suppressions, déplacements — sans un écart entre ce modèle, un arbre de référence et la vue qu'AppKit reconstruit à partir des seuls indices qu'on lui envoie, mise en forme des lignes comprise.
Quand l'animation n'est pas sûre
Un indice qu'AppKit ne connaît pas lève une exception Objective-C, qui arrête une application Xojo. AppKit ne connaît les enfants que d'un parent affiché et déplié, et rien avant son premier chargement. Hors de ces cas, l'arbre est rechargé à la place — sans perte : les clés étant liées au numéro, le dépliement et la sélection survivent.

Glisser des nœuds

AllowsRowReordering As Boolean
Hérité du tableau, et valable pour l'arbre depuis le 14 septembre 2026, par ses propres méthodes de source : outlineView:pasteboardWriterForItem:, validateDrop:proposedItem:proposedChildIndex: et acceptDrop:item:childIndex:. On dépose entre deux nœuds, ou sur un nœud pour l'y ranger en dernier — l'index proposé vaut alors -1.Le dépôt dans sa propre descendance est refusé dès le survol, et le curseur le montre. Plusieurs nœuds se déposent en bloc, dans l'ordre de l'écran : chacun est rangé tour à tour juste avant une ancre — le premier frère non glissé qui suit le point de dépôt —, et un nœud dont un ancêtre est aussi glissé voyage avec lui. Prouvé sur 14 407 dépôts aléatoires contre un calcul indépendant — retirer le bloc, le réinsérer d'un coup —, sans un écart. Le type glissé est propre aux arbres, et un glisser venu d'une autre vue est ignoré : un numéro de nœud n'a de sens que dans son arbre.
Event NodesMoved(nodes() As NativeOutlineNode, newParent As NativeOutlineNode, index As Integer)
Les nœuds déposés, dans l'ordre de l'écran, leur nouveau parent — Nil pour la racine — et la position du premier. Le pendant de RowsMoved ; le bloc reste sélectionné, et un dépôt sur un nœud replié le déplie.

Parcourir

Function Contains(node As NativeOutlineNode) As Boolean
Function NodeCount() As Integer
Function ParentOf(node As NativeOutlineNode) As NativeOutlineNode
Function ChildCount(parent As NativeOutlineNode) As Integer
Function ChildAt(parent As NativeOutlineNode, index As Integer) As NativeOutlineNode
Function IndexOf(node As NativeOutlineNode) As Integer
Nil désigne la racine. Contains est vrai pour un nœud de cet arbre qui n'en a pas été retiré ; ParentOf rend aussi Nil pour un nœud étranger, et c'est Contains qui tranche. IndexOf donne l'indice qu'attendent InsertNode et MoveNode.
Function RowOf(node As NativeOutlineNode) As Integer
Function NodeAt(row As Integer) As NativeOutlineNode
Le lien avec les méthodes de ligne héritées, qui prennent une ligne de stockage.La ligne change dès qu'on insère, retire ou déplace ailleurs : ne pas la garder, garder le nœud.

Cellules, sélection et repli, en nœuds

Function NodeCell(node, column) As String · Sub SetNodeCell(node, column, value)
Function NodeChecked(node, column) As Boolean · Sub SetNodeChecked(node, column, checked)
Sub SetNodeIcon(node, symbolName) · Sub SetNodeSubtitle(node, column, subtitle)
Sub SetNodeBold(node, column, bold) · Sub SetNodeTextColor(node, column, textColor)
Sub SetNodeBackground(node, column, backColor) · Sub ReloadNode(node)
La version nœud de chaque méthode de ligne héritée : RowOf fait la traduction. ReloadNode redessine un nœud déjà affiché — après un SetNodeIcon, par exemple.
Sub SelectNode(node) · Function SelectedNode() As NativeOutlineNode
Function SelectedNodes() As NativeOutlineNode() · Sub ScrollToNode(node)
Sub ExpandNode(node, withChildren As Boolean = False) · Sub CollapseNode(node, withChildren As Boolean = False)
Function IsNodeExpanded(node) As Boolean · Sub ExpandAll() · Sub CollapseAll()
SelectNode(Nil) désélectionne. Un nœud sous un parent replié n'a pas de ligne à l'écran : il ne se sélectionne pas.

Événements

Event NodeSelectionChanged(node As NativeOutlineNode)
Event NodeCellChanged(node As NativeOutlineNode, column As Integer, value As String)
Event NodeDoubleClicked(node As NativeOutlineNode)
Levés en plus de ceux du tableau, qui donnent une ligne de stockage. Préférer ceux-ci : une ligne change dès qu'on insère ou déplace.
Controls

NativeOutlineNode

classe

Un nœud d'arborescence — une poignée, pas une ligne. NativeOutlineView le rend à chaque ajout et l'attend partout où il faut désigner un nœud. Son numéro ne change jamais : il reste valable après une insertion, une suppression ou un déplacement ailleurs dans l'arbre.

Pourquoi un type propre

Un numéro stable resté Integer aurait compilé partout, et coïncidé avec la ligne… jusqu'à la première suppression, puis tout faussé en silence. Avec un type propre, le compilateur désigne chaque endroit à revoir. Le lien vers l'arbre est faible : garder des nœuds ne retient pas l'arbre en vie.

Méthodes

Function Id() As Integer
Un numéro propre à l'arbre, jamais réutilisé — pas même après RemoveAllRows. Pour comparer deux nœuds, Is suffit : l'arbre rend toujours le même objet pour le même nœud.
Function IsValid() As Boolean
Faux si le nœud a été retiré, si l'arbre a été vidé, ou s'il n'existe plus.
Function Tree() As NativeOutlineView
Function BelongsTo(tree As NativeOutlineView) As Boolean
L'arbre du nœud, par un lien faible ; Nil s'il a disparu.
Sub Constructor(owner As NativeOutlineView, nodeId As Integer)
Réservé à l'arbre. Un nœud fabriqué à la main, même avec un numéro existant, n'est pas reconnu : Contains exige l'objet que l'arbre a rendu.
Controls

NativePathControl

classe

NSPathControl : la barre de chemin du Finder. Chaque composant est cliquable, le contrôle accepte le glisser-déposer, et en style PopUp éditable il ouvre lui-même un NSOpenPanel filtré.

Constructeur

Sub Constructor(style As Styles = Styles.Standard)

Méthodes

Function Handle() As Ptr
Sub SetAllowedTypes(ParamArray types() As String)
Extensions ou UTI. Sert au NSOpenPanel que le contrôle ouvre tout seul en style PopUp éditable ; sans liste, tout est accepté.
Sub SetAllowedTypeArray(types() As String)
La forme tableau, pour NativePathBarControl. Un tableau vide pose nil : pour l'en-tête, une liste vide n'autoriserait rien.
Sub SetEditable(editable As Boolean)
Combiné au style PopUp, ajoute l'entrée « Choisir… » qui ouvre le panneau.
Sub SetPlaceholder(text As String)

Propriétés

Path As String
Style As Styles
Value As FolderItem

Événements

  • Event Changed(item As FolderItem, path As String)
  • Event DoubleClicked(item As FolderItem, path As String)

Énumérations

StylesStandard=0PopUp=2
Controls

NativeSegmentedControl

classe

NSSegmentedControl avec les huit styles, les quatre modes de suivi et la répartition. Attention : l'énumération NSSegmentStyle a un trou en 7Separated vaut 8.

Constructeur

Sub Constructor(labels() As String, selectOne As Boolean = True)

Méthodes

Function Handle() As Ptr
Function IsSelected(index As Integer) As Boolean
N'a de sens qu'en mode SelectAny : ailleurs, SelectedIndex suffit.
Sub Refit()
À rappeler après un changement de style, de symbole ou de largeur : la taille idéale dépend des trois.
Sub SetDistribution(distribution As Distributions)
macOS 10.13+. Décide du sort de l'espace restant : laissé vide, réparti, ou segments égalisés. Sans effet en dessous.
Sub SetSelected(index As Integer, selected As Boolean)
Le pendant d'IsSelected, pour cocher plusieurs segments en SelectAny.
Sub SetSymbol(index As Integer, symbolName As String, accessibilityDescription As String = "")
Symbole SF à la place — ou à côté — du libellé. Un symbole introuvable laisse simplement le segment tel quel.
Sub SetWidth(index As Integer, width As Double)
0 rend le segment dynamique : c'est alors la distribution qui décide.

Propriétés

SelectedIndex As Integer
Style As Styles
TrackingMode As TrackingModes
BorderShape As NativeControlHost.BorderShapes
macOS 26. Le SÉLECTEUR est interrogé, pas le numéro de version : sur un système antérieur le contrôle garde son aspect au lieu de lever.

Événements

  • Event Changed(index As Integer)

Énumérations

DistributionsFit=0Fill=1FillEqually=2FillProportionally=3
StylesAutomatic=0Rounded=1TexturedRounded=2RoundRect=3TexturedSquare=4Capsule=5SmallSquare=6Separated=8
TrackingModesSelectOne=0SelectAny=1Momentary=2MomentaryAccelerator=3
Controls

NativeSlider

classe

NSSlider, éventuellement encadré de deux symboles SF dans une vue hôte — le motif d'Aperçu ou de Photos. Handle rend alors la vue hôte, SliderHandle la glissière.

Constructeur

Sub Constructor(minimum As Double = 0, maximum As Double = 100, value As Double = 50, width As Double = 120, leadingSymbol As String = "", trailingSymbol As String = "")

Si des symboles SF sont fournis, la glissière est encadrée par deux petites images dans une vue hôte — le motif d'Aperçu ou de Photos. Handle renvoie alors cette vue hôte, SliderHandle la glissière elle-même.

Méthodes

Function Handle() As Ptr
La vue à confier à l'item : l'ensemble icônes + glissière s'il y a lieu.
Sub SetTicks(count As Integer, valuesOnly As Boolean = False)
Graduations sous la glissière. valuesOnly force les valeurs à s'y aligner.
Sub SetTooltip(text As String)
Function SliderHandle() As Ptr

Propriétés

Value As Double
TintProminence As NativeControlHost.TintProminences
macOS 26. Le SÉLECTEUR est interrogé, pas le numéro de version : sur un système antérieur le contrôle garde son aspect au lieu de lever.
NeutralValue As Double
macOS 26. Le SÉLECTEUR est interrogé, pas le numéro de version : sur un système antérieur le contrôle garde son aspect au lieu de lever. L'ORIGINE du remplissage, pas une borne : un curseur de balance se remplit depuis le centre plutôt que depuis la gauche.

Événements

  • Event Changed(value As Double)
Controls

NativeProgressIndicator

classe

NSProgressIndicator, barre ou roue, déterminé ou non.

Constructeur

Sub Constructor(indeterminate As Boolean = True, width As Double = 120)

Méthodes

Function Handle() As Ptr
Sub StartAnimation()
Sub StopAnimation()

Propriétés

Value As Double
0 à 100 par défaut (minValue/maxValue non modifiés).
Controls

NativeTokenField

classe

NSTokenField : le champ à jetons du « À : » de Mail. Son objectValue n'est pas une chaîne mais un NSArray — toute la différence avec le NSTextField dont il hérite. La complétion puise dans une liste fournie, servie par le delegate.

Constructeur

Sub Constructor(placeholder As String = "")

NSTokenField hérite de NSTextField, mais son objectValue n'est PAS une chaîne : c'est un NSArray. Lire stringValue ne rend que la représentation aplatie, séparée par le jeu de caractères de tokenisation.

Méthodes

Function Handle() As Ptr
Sub SetCompletions(ParamArray candidates() As String)
La liste dans laquelle la complétion puise. Vide = pas de complétion.
Sub SetTokenizingCharacter(separator As String = ",")
Le caractère qui valide un jeton. Virgule par défaut chez AppKit ; le point-virgule est fréquent pour des adresses.
Sub SetTokens(ParamArray values() As String)
Sub SetTokenArray(values() As String)
Sub SetCompletionArray(candidates() As String)
Les formes tableau de SetTokens et SetCompletions : un ParamArray ne se transmet pas d'une méthode à l'autre, et NativeTokenFieldControl relaie des listes lues dans l'Inspecteur.
Function Tokens() As String()
objectValue est un NSArray, PAS une chaîne — c'est toute la différence avec le NSTextField dont NSTokenField hérite. Lire stringValue ne rendrait que la version aplatie, recollée par le caractère de tokenisation.

Propriétés

Placeholder As String
Style As Styles

Événements

  • Event Changed(tokens() As String)

Énumérations

StylesStandard=0None=1Rounded=2Squared=3PlainSquared=4
Controls

NativeTextView

classe

NSTextView dans son NSScrollView : un vrai éditeur de texte riche. ShowFormatBar allume usesInspectorBarla barre RTF du système, la plus complète : police et taille affichées, barré, couleur de fond, et déjà localisée — mais elle se pose sur la fenêtre, pas sur l’éditeur. Les mêmes commandes sont aussi exposées une à une, pour composer une barre à soi.

Constructeur

Sub Constructor(width As Double = 520, height As Double = 260)

Le scroll view sert au défilement et à la RÈGLE. Il n'est PAS nécessaire à la barre de format — voir ShowFormatBar, qui n'est pas ce qu'on croit.

Méthodes

Function Handle() As Ptr
Le SCROLL VIEW — c'est lui qu'on héberge, pas la vue de texte. Même convention que NativeSlider avec sa vue hôte.
Sub LoadRTF(file As FolderItem)
Remplace tout le contenu. Les primitives RTF vivent déjà dans le module Cocoa : inutile de les redéclarer ici.
Sub SaveRTF(file As FolderItem)
Sub SetAdaptiveDarkMode(adaptive As Boolean)
macOS 10.14+. Sans lui, un document RTF dont les couleurs sont écrites en dur reste illisible en mode sombre : le système ne les remappe pas.
Sub SetBorder(kind As Borders)
Quand l'éditeur est logé dans un cadre qui dessine déjà sa bordure, celle du scroll view fait double emploi.
Sub SetEditable(editable As Boolean, richText As Boolean = True)
Sub SetOptions(spellChecking As Boolean = True, linkDetection As Boolean = True, importsGraphics As Boolean = True, fontPanel As Boolean = True)
importsGraphics autorise le dépôt d'images dans le texte ; fontPanel relie l'éditeur au panneau Police du système (Cmd-T).
Sub SetWritingTools(behavior As WritingTools)
macOS 15+. None (-1) exclut la vue des outils d'écriture ; Complete demande la retouche en ligne, Limited le panneau en surimpression.
Sub SetRulerAccessory(view As Ptr)
La TROISIÈME voie, et la seule qui loge une barre DANS la zone de texte : la vue accessoire de la règle. Vérifié en Objective-C — l'accessoire devient sous-vue de la NSRulerView, donc du scroll view ; aucun accessoire de fenêtre n'est créé et la vue de contenu ne bouge pas.PIÈGE : setAccessoryView: LÈVE UNE EXCEPTION si le clientView de la règle n'a pas été posé — « you must set the client view of the ruler before you can have an accessory view ». Ce n'est pas un no-op, c'est un plantage. À savoir aussi : la règle graduée vient AVEC. Dans l'essai, une règle de 60 points pour 28 d'accessoire. Pour une barre seule dans un cadre, la barre maison de NativeRichTextEditor reste préférable.
Sub ShowFindBar(visible As Boolean)
La barre de recherche de TextEdit, Cmd-F. incrementalSearching surligne au fil de la frappe.
Sub ShowFormatBar(visible As Boolean)
LA barre RTF de TextEdit : police, taille, gras/italique/souligné, couleurs du texte et du fond. C'est usesInspectorBar, apparu en 10.7.MAIS ELLE N'APPARTIENT PAS À L'ÉDITEUR. Vérifié en Objective-C : AppKit installe un NSTitlebarAccessoryViewController sur la FENÊTRE — vue __NSInspectorBarView, 28 points, layoutAttribute 4, donc sous la barre d'outils et sur toute la largeur — et RÉTRÉCIT la vue de contenu d'autant. L'éteindre retire l'accessoire et rend les 28 points. Trois conséquences : 1) la barre ne peut pas être confinée dans un cadre : elle est au niveau de la fenêtre, exactement comme dans TextEdit ; 2) toute mise en page qui positionne ses vues elle-même doit être refaite après l'appel, sinon la barre recouvre le contenu au lieu de le pousser ; 3) ni le scroll view ni l'ordre des appels n'y changent quoi que ce soit — testé sans scroll view, réglé avant setDocumentView:, et hors fenêtre : l'accessoire est installé dans les trois cas.
Sub ShowRuler(visible As Boolean)
La règle graduée, avec taquets et retraits. Elle partage la zone de la barre de format : les deux peuvent coexister, l'une au-dessus de l'autre.
Sub ChangeSize(bigger As Boolean)
Les actions « Plus grand » / « Plus petit » du menu Format : c'est le NSFontManager qui les exécute, d'après le TAG de l'objet qu'on lui passe.
Function IsBold() As Boolean
Function IsItalic() As Boolean
Sub SetAlignment(alignment As Alignments)
Actions natives de NSText : elles savent déjà quels paragraphes toucher.
Sub ShowColorPanel()
Le panneau envoie changeColor: au premier répondant : c'est la NSTextView qui applique la couleur, on n'a rien à recopier.
Sub ShowFontPanel()
Sub ToggleBold()
Sub ToggleBullets()
La seule commande de la barre qui n'ait PAS d'équivalent natif : AppKit n'expose qu'orderFrontListPanel:, un panneau, pas une bascule. On préfixe donc « •⇥ » à chaque paragraphe de la sélection, ou on l'enlève.
Sub ToggleItalic()
Sub ToggleUnderline()
Action native, elle : NSText la fournit directement.
Function TextViewHandle() As Ptr
La NSTextView elle-même, à passer aux primitives du module Cocoa — ApplyColor, SetTextColorRange, TextLength.
Sub Highlight(scheme As HighlightSchemes = HighlightSchemes.Default)
macOS 15. Le surligneur de Notes. La couleur ne se passe PAS en argument : « The sender should be a menu item with a representedObject of type NSTextHighlightColorScheme » — on fabrique donc un item de menu jetable qui la porte. Rappeler la même couleur retire le surlignage.
Function HighlightSupported() As Boolean
Pour ADAPTER l'interface, pas pour garder l'appel.
Function WritingToolsActive() As Boolean
macOS 15. Les outils réécrivent-ils le texte EN CE MOMENT ? C'est le moment de suspendre un enregistrement automatique ou une analyse du contenu, qui porteraient sur un état intermédiaire.
Sub SetAllowedWritingToolsResults(options As Integer)
macOS 15. Ce que les outils ont le droit de RENDRE. Champ de bits dont les valeurs s'impliquent : List et Table impliquent RichText, et PresentationIntent (macOS 26) implique les trois. Un éditeur qui ne sait pas afficher de tableau a tout intérêt à ne pas s'en faire proposer.L'ASPECT du surlignage — textHighlightAttributes — n'est délibérément PAS exposé. Essayé puis retiré : le fond ainsi posé se peint par-dessus les glyphes et masque le texte, avec les deux couleurs comme avec une seule ; forcer un redessin l'aggrave, drawTextHighlightBackgroundForTextRange: étant une méthode de dessin qu'on ne peut pas appeler hors de sa passe. Les schémas nommés de Highlight, eux, fonctionnent.
Sub ShowWritingTools()
macOS 15.2. Adresse showWritingTools: directement à la vue, sans dépendre du premier répondant.

Propriétés

Text As String
Le texte NU : les attributs sont perdus. Pour conserver le formatage, passer par SaveRTF.

Événements

  • Event Changed()

Énumérations

WritingToolsResultsDefault=0PlainText=1RichText=2List=4Table=8PresentationIntent=16
BordersNone=0Line=1Bezel=2Groove=3
AlignmentsLeft=0Center=1Right=2Justified=3
WritingToolsNone=-1Automatic=0Complete=1Limited=2
Controls

NativeRichTextEditor

classe

L'éditeur de ressource complet : un cadre arrondi, une barre de commandes grise, la zone de saisie, un filet, un pied de page avec son bouton. Entièrement bâti sur NativeBox — donc sur de vraies NSColor, qui suivent le mode sombre seules, là où un CGColor posé dans un calque reste figé. ShowCommandBar le rend exclusif de la barre native du système, qui, elle, appartient à la fenêtre.

Constructeur

Sub Constructor(width As Double = 620, height As Double = 320)

Tout est bâti en NSBox et non en calques : un NSBox peint avec de VRAIES NSColor, donc il suit le mode sombre tout seul. Un CGColor posé dans un CALayer est figé au moment où on l'écrit et ne se met jamais à jour.

Méthodes

Function Editor() As NativeTextView
La vue de texte, pour tout ce que la barre ne couvre pas : Text, LoadRTF, SaveRTF, ShowRuler, et la barre native ShowFormatBar.
Function Handle() As Ptr
Sub ShowCommandBar(visible As Boolean)
La barre du composant et la barre native du système sont des ALTERNATIVES, pas des calques : la native se pose sur la fenêtre (voir NativeTextView.ShowFormatBar), celle-ci vit dans le cadre. Les afficher toutes les deux donne deux rangées de commandes qui font la même chose.
Sub SetFooter(text As String, buttonTitle As String = "")
Le pied de page : une explication à gauche, un bouton à droite. Passer un titre vide n'affiche pas de bouton.

Événements

  • Event Changed()
  • Event CommandUsed(index As Integer)
  • Event FooterPressed()
Controls

NativeDropView

classe

Une vue qui reçoit le glisser-déposer — le puits de fichiers que Xojo n'a pas. La vue est elle-même la destination, il n'y a donc pas d'objet cible séparé. Le sens inverse est assuré par NativeDragSource.

Constructeur

Sub Constructor(width As Double = 300, height As Double = 140, accepts As Kinds = Kinds.FilesAndText)

Ici la VUE est elle-même la destination : pas d'objet cible séparé, donc le registre de Cocoa associe directement le pointeur de vue à l'objet Xojo.

Méthodes

Function Handle() As Ptr
Sub SetAccepts(kinds As Kinds)
Réenregistre les types acceptés. unregisterDraggedTypes d'abord : sinon les anciens types resteraient en plus des nouveaux, et la vue continuerait d'accepter ce qu'on vient de lui refuser.

Propriétés

Operation As Operations
L'opération annoncée au système : elle décide du CURSEUR que voit l'utilisateur — le « + » de la copie, la flèche courbe de l'alias.

Événements

  • Event Dropped(files() As FolderItem, text As String) As Boolean
  • Event Entered(hasFiles As Boolean, hasText As Boolean) As Boolean
  • Event Exited()

Énumérations

KindsFilesOnly=0TextOnly=1FilesAndText=2
OperationsNone=0Copy=1Link=2Generic=4Move=16
Controls

NativeDragSource

classe

Une vue qui émet un glissement — vers le Finder ou une autre application. Trois surcharges, aucune décorative : un mouseDown: vide (sans lui, NSResponder fait remonter l'événement et la vue ne suit jamais le geste), mouseDragged: (où la session démarre, car beginDraggingSessionWithItems:event:source: exige un NSEvent), et hitTest: rendant SelfNSControl interceptant mouseDown:, une simple étiquette posée dans le puits casserait le glissement.

Constructeur

Sub Constructor(width As Double = 220, height As Double = 130)

Trois overrides, et aucun n'est décoratif — chacun répond à un fait mesuré :

mouseDown:

NSView ne l'implémente pas : sans override, NSResponder fait REMONTER l'événement au nextResponder et la vue ne suit jamais le geste. Ce corps vide est donc un puits volontaire. mouseDragged: c'est là que la session démarre — beginDraggingSession… exige un NSEvent, on ne peut pas glisser sans geste. hitTest:

Méthodes

Sub AddContent(view As Ptr)
Le puits ne dessine rien de lui-même : on y pose ce qu'on veut montrer — une NativeImageView, une NativeBox, une étiquette. hitTest: garantit que le contenu ne volera pas le geste, quel qu'il soit.
Function Handle() As Ptr
Sub SetFiles(files() As FolderItem)
Ce que le glissement TRANSPORTE. Remplace un contenu précédent.
Sub SetText(value As String)

Propriétés

Operation As UInteger
Ce que la SOURCE autorise. La destination choisit dans cet ensemble : proposer Copy seul, c'est interdire le déplacement.
PreviewSide As Double
StackMultipleItems As Boolean

Événements

  • Event Ended(operation As UInteger)
  • Event CancelDrag() As Boolean

Constantes

  • kFormationStack = 4
  • OperationCopy = 1
  • OperationLink = 2
  • OperationMove = 16
Controls

NativeImageView

classe

NSImageView. Xojo a DesktopImageViewer, mais sans les modes de mise à l'échelle, sans cadre, sans teinte de contenu et sans symbole SF. ShowFile affiche le contenu si c'est une image et retombe sinon sur l'icône du Finder — laquelle vaut pour tout : dossier, application, document inconnu.

Constructeur

Sub Constructor(width As Double = 96, height As Double = 96, scaling As Scalings = Scalings.ProportionallyUpOrDown)

Méthodes

Sub Clear()
Function Handle() As Ptr
Sub ShowFile(item As FolderItem)
Aperçu du contenu si c'est une image, sinon l'icône du Finder — laquelle vaut pour TOUT : dossier, application, document inconnu. initWithContentsOfFile rend Nil pour un dossier comme pour un fichier texte, d'où le repli.
Sub ShowFinderIcon(item As FolderItem)
L'icône que le Finder affiche pour cet élément précis — pas celle de son type. Un dossier, un paquet, une application ont chacun la leur.
Function ShowThumbnail(item As FolderItem, maxSide As Double = 512) As Boolean
La VRAIE vignette QuickLook — la première page d'un PDF, l'image elle-même, le rendu 3D d'un STL — et non l'icône du type.POURQUOI CETTE VOIE, et pas QLPreviewView : un aperçu VIVANT installe une NSRemoteView servie par SceneKitQLPreviewExtension, et afficher un modèle 3D détruit alors DÉFINITIVEMENT le glisser-déposer du processus — mesuré, rien ne le rétablit hormis quitter. La vignette, elle, passe par SceneKitQLThumbnailExtension, celui que le Finder emploie sans cesse : elle rend une IMAGE, ne pose aucune vue dans notre fenêtre, et ne laisse aucun processus derrière elle. QLThumbnailImageCreate est déprécié depuis 10.15 mais toujours présent, et il est SYNCHRONE — 43 ms sur un STL — là où l'API moderne exige un bloc et un rappel hors du thread principal. Le jour où il disparaîtra, il rendra Nil et l'on retombera sur l'icône : la panne est déjà prévue. UN SEUL CÔTÉ, et c'est mesuré : la taille demandée est une BOÎTE dans laquelle la vignette doit tenir, et le générateur 3D rend du 4:3. Une boîte plus étroite que ce rapport le fait échouer sans rien dire — 840 x 340 rend Nil, 512 x 512 rend 512 x 384. On demande donc un CARRÉ, qui contient n'importe quel rapport naturel, et l'on laisse la vue mettre à l'échelle. Au-delà de 1024, le générateur plafonne de lui-même.
Sub ShowSymbol(symbolName As String, accessibilityDescription As String = "")
Sub SetTint(useTint As Boolean, tint As Color = &c000000)
10.14+, et n'agit que sur les images « template » — un symbole SF, typiquement.

Propriétés

FrameStyle As Frames
Scaling As Scalings

Énumérations

FramesNone=0Photo=1GrayBezel=2Groove=3Button=4
ScalingsProportionallyDown=0AxesIndependently=1None=2ProportionallyUpOrDown=3
Controls

NativeTableView

classe

Un NSTableView à base de vues : chaque cellule est une vraie vue, pas un dessin — d'où les cases à cocher, menus, champs éditables et jauges qu'on y met, tout ce que DesktopListBox ne sait pas faire. Fond, couleur de texte et gras se posent par cellule, et le tri les emporte avec leur ligne. Le tri lui-même passe par sortDescriptorPrototype : la flèche est dessinée par AppKit. Une icône SF Symbols se pose par ligne au début de la première colonne (SetRowIcon). C'est aussi la classe de base de NativeOutlineView : ses méthodes protégées — source de données, colonne hiérarchique, vidage, tri, primitives de stockage, traduction ligne visible ↔ ligne de stockage (ModelRow, VisibleRow), relais d'événements — y sont prévues pour être redéfinies. Ces deux traductions rendent justes, pour un arbre, la cellule modifiée, la sélection simple et multiple, le défilement et le rechargement d'une ligne ; et MoveRowModel déplace toute la ligne, mise en forme comprise — la première version perdait fond, couleur, gras, alignements et sous-titres.

Constructeur

Sub Constructor(width As Double = 480, height As Double = 240, viewClass As String = "NSTableView", dsClass As String = "VDSTableDS")

NativeSidebarBase enveloppe aussi un NSTableView, mais pour une liste source : une colonne, pas d'en-tête, pas de tri. Les deux ne se recouvrent pas.

Les DEUX DERNIERS paramètres sont réservés aux sous-classes. AppKit fait dériver NSOutlineView de NSTableView : NativeOutlineView en fait autant, et n'a donc à fournir que la classe de vue et le nom de sa source de données.

Méthodes

Sub AddColumn(title As String, width As Double = 140, sortable As Boolean = False, kind As CellKinds = CellKinds.Text, minWidth As Double = 40)
Les colonnes AVANT les lignes : le stockage est plat — indice = ligne × nombre de colonnes + colonne —, en ajouter une après coup décalerait tout. Plutôt que de corrompre en silence, on vide.
Sub AddRow(ParamArray cells() As String)
La forme commode. Le travail est dans AddRowArray : un ParamArray ne se transmet pas d'une méthode à l'autre, et une sous-classe a besoin de la forme tableau — AddNode y ajoute simplement un parent.
Function CellAt(row As Integer, column As Integer) As String
Function CellChecked(row As Integer, column As Integer) As Boolean
Une case cochée n'a pas de stockage à part : elle vaut « 1 » dans la même grille de chaînes que tout le reste. Une seule source de vérité.
Function ColumnCount() As Integer
Function Handle() As Ptr
La vue à POSER : le NSScrollView, pas la table — celle-ci est son documentView et n'a pas de taille propre utile.
Sub Reload()
Sub RemoveAllRows()
Function RowCount() As Integer
Sub ScrollTo(row As Integer)
Sub SelectRow(row As Integer)
Sub SetCell(row As Integer, column As Integer, value As String)
Sub SetCellBackground(row As Integer, column As Integer, backColor As Color)
Un fond POSÉ ne suit pas le mode sombre : c'est une couleur choisie par l'application, pas une couleur système. À réserver au sens — un retard en rouge, un accord en vert —, jamais à la décoration.
Sub ClearCellBackground(row As Integer, column As Integer)
Sub SetCellTextColor(row As Integer, column As Integer, textColor As Color)
Sub SetCellBold(row As Integer, column As Integer, bold As Boolean)
Sub SetCellChecked(row As Integer, column As Integer, checked As Boolean)
Sub SetCellAlignment(row As Integer, column As Integer, alignment As Alignments)
Surcharge la colonne pour CETTE cellule. Utile là où une valeur change de nature au sein d'une même colonne — un nombre parmi du texte, un total en bas d'une liste.
Sub ClearCellAlignment(row As Integer, column As Integer)
Rend la cellule à l'alignement de sa colonne.
Sub SetCellVerticalAlignment(row As Integer, column As Integer, alignment As VerticalAlignments)
Sub ClearCellVerticalAlignment(row As Integer, column As Integer)
Sub SetColumnVerticalAlignment(column As Integer, alignment As VerticalAlignments)
AppKit ne propose RIEN pour cela : un NSTextField centre son texte dans le cadre qu'on lui donne, et c'est tout. L'alignement vertical se fait donc en plaçant le CADRE dans la cellule, pas en réglant une propriété.
Sub SetColumnAlignment(column As Integer, alignment As Alignments)
Sub SetColumnChoices(column As Integer, ParamArray items() As String)
Les choix d'une colonne de type Popup. Stockés joints par un saut de ligne : un tableau de tableaux se prête mal au format texte d'une classe Xojo.
Sub SortBy(column As Integer, ascending As Boolean = True)
Le tri par défaut : ALPHABÉTIQUE et insensible à la casse, puisque le modèle ne stocke que du texte. Pour trier des nombres ou des dates, il faut intercepter SortChanged et rendre True.Les STYLES suivent les lignes : un fond rouge posé sur « en retard » doit rester avec elle, pas rester à la troisième place du tableau. Une ARBORESCENCE refuse : ses lignes sont des nœuds, et la table des parents désigne les nœuds par leur INDICE. Les permuter romprait le lien parent-enfant en silence.
Function TableHandle() As Ptr
Sub SetRowIcon(row As Integer, symbolName As String)
Un symbole système au début de la PREMIÈRE colonne. Le nom est celui de SF Symbols — « folder », « doc.text » — et une chaîne vide l'enlève.

Propriétés

SelectedRow As Integer lecture seule
Pour une ARBORESCENCE, la ligne visible dépend de ce qui est déplié : CurrentRow rend alors le nœud, qui est l'identité stable.
BezeledEditableCells As Boolean
DoubleClickAction As Boolean
L'ÉDITION d'une cellule démarre traditionnellement au second clic, et l'action de double-clic de la table vise le même geste. Les deux se disputent donc la souris sur une colonne éditable : débrayer l'action rend la main à l'édition. Un SEL nul désarme proprement : AppKit n'envoie plus rien.
AlternatingRowColors As Boolean
GridMask As UInteger
AllowsMultipleSelection As Boolean
RowHeight As Double
Style As Styles
setStyle: n'existe qu'à partir de macOS 11 : sur un système antérieur la table garde son aspect d'origine plutôt que de lever.
ShowsHeader As Boolean
Masquer un en-tête, c'est poser Nil : AppKit replie alors la zone que le NSScrollView lui réservait. Le rendre, c'est REMETTRE celui qu'on avait mis de côté au départ. En bâtir un neuf marche aussi, MAIS il faut lui donner une hauteur : un NSTableHeaderView à cadre nul est bel et bien installé, et le scroll view rétablit sa zone — d'une hauteur de zéro. On voit donc « rien », sans la moindre erreur pour le signaler.

Événements

  • Event CellChanged(row As Integer, column As Integer, value As String)
  • Event RowDoubleClicked(row As Integer)
  • Event SelectionChanged(row As Integer)
  • Event SortChanged(column As Integer, ascending As Boolean) As Boolean

Énumérations

AlignmentsLeft=0Center=1Right=2
VerticalAlignmentsTop=0Middle=1Bottom=2
CellKindsText=0Editable=1Checkbox=2Popup=3Level=4
StylesAutomatic=0FullWidth=1Inset=2SourceList=3Plain=4

Constantes

  • GridNone = 0
  • GridVertical = 1
  • GridHorizontal = 2

Animations de lignes

Sub InsertRow(index As Integer, cells() As String, animation As Animations = Animations.SlideDown)
Insère une ligne À UN INDICE et l'anime, là où AddRow ajoute en fin et oblige à tout recharger.LE MODÈLE D'ABORD, AppKit ensuite : insertRowsAtIndexes: fait aussitôt demander la nouvelle ligne à la source de données ; si le stockage n'est pas déjà à jour, la table lit une ligne qui n'existe pas.
Sub RemoveRow(index As Integer, animation As Animations = Animations.SlideUp)
Retire une ligne et l'anime.L'en-tête précise que les indices passés à removeRowsAtIndexes: se rapportent à l'état AFFICHÉ, pas à l'état final. Sans conséquence pour une ligne à la fois, mais il en irait autrement pour plusieurs.
Sub MoveRow(fromIndex As Integer, toIndex As Integer)
Déplace une ligne. Pas d'option d'animation, et ce n'est pas un oubli : moveRowAtIndex:toIndex: n'en accepte pas — la vue n'est ni détruite ni recréée, c'est la même qui voit sa position changer, et le déplacement s'anime de lui-même.
Sub BeginUpdates()
Sub EndUpdates()
macOS 10.7. Plusieurs changements s'animent ENSEMBLE entre les deux, l'état de départ étant celui qui précède BeginUpdates. Les appels sont imbriquables.Inutile pour un changement isolé — l'en-tête le dit — mais indispensable dès qu'il y en a deux, faute de quoi chacun s'anime pour son compte et le résultat saute.
Sub ReloadRow(row As Integer)
macOS 10.6. Redessine UNE ligne au lieu de recharger la table entière : la sélection, le défilement et les vues des autres lignes sont préservés. Vaut aussi pour une arborescence.
Enum Animations
None, Fade, Gap, les quatre glissements et les quatre combinaisons avec le fondu.Les options de glissement ne sont PAS des drapeaux, malgré les apparences. Mesuré : SlideUp 16, SlideDown 32, SlideLeft 48, SlideRight 64 — et SlideUp Or SlideLeft donne 48, c'est-à-dire SlideLeft. C'est un CHAMP, et l'en-tête le confirme : « only one option from this group may be specified at a time ». Seul le fondu se combine, d'où les combinaisons toutes faites plutôt qu'une addition qui donnerait silencieusement la mauvaise valeur.

Cellule à deux lignes

Sub SetCellSubtitle(row As Integer, column As Integer, subtitle As String)
Function CellSubtitle(row As Integer, column As Integer) As String
La seconde ligne d'une cellule CellKinds.Subtitle — le motif d'une liste façon Mail : un titre, et sous lui une ligne plus petite et plus pâle. Rangée dans son propre tableau parallèle, comme toutes les autres propriétés par cellule, plutôt que de coder deux valeurs dans une chaîne — ce qui ferait rendre « titre + séparateur + sous-titre » par CellAt.Il faut de la hauteur : deux lignes ne tiennent pas dans les 22 points d'une ligne standard. Sous RowHeight = 34, le sous-titre est rogné.

Colonnes et sélection

Function SelectedRows() As Integer()
Sub SelectRows(rows() As Integer, extend As Boolean = False)
Function IsRowSelected(row As Integer) As Boolean
AllowsMultipleSelection existait déjà, mais rien ne permettait de LIRE la sélection — une sélection multiple qu'on peut activer sans pouvoir la lire est une demi-fonction. SelectedRow, lui, ne rend que la ligne courante.Le parcours du NSIndexSet se borne par le nombre de lignes plutôt que de comparer à NSNotFound. Celui-ci vaut NSIntegerMax — 9223372036854775807 — qu'un Double ne peut pas représenter : il arrondit à …808, la comparaison ne serait jamais vraie et la boucle tournerait sans fin. Vérifié, pas supposé.
AllowsColumnReordering As Boolean
AllowsColumnResizing As Boolean
Déplacer les colonnes à la souris, les redimensionner en tirant entre les en-têtes. Les deux valent True par défaut chez AppKit, et cette classe garde ce défaut.Une colonne ne se redimensionne que si elle l'autorise pour son compte — voir -[NSTableColumn setResizingMask:]. Et le réglage programmatique reste possible quelle que soit la valeur.
Sub SetIntercellSpacing(horizontal As Double, vertical As Double)
Function IntercellSpacing() As Cocoa.NSSize
L'espace entre cellules. Le défaut d'AppKit est 3 × 2.La hauteur s'AJOUTE à RowHeight : le rectangle réel d'une ligne vaut rowHeight plus intercellSpacing.height, ce que l'en-tête précise à propos de rectOfRow:.
Event ColumnClicked(column As Integer)
Event ColumnDragged(column As Integer)
Le clic sur un en-tête, distinct du tri, et la fin d'un déplacement de colonne.
Event ShouldRefuseColumnReorder(column As Integer, toColumn As Integer) As Boolean
Le veto. Il demande ce qu'il faut REFUSER, pas ce qu'il faut permettre, et l'inversion est délibérée : un RaiseEvent sans gestionnaire branché rend False, donc poser la question à l'endroit interdirait tout déplacement par défaut. Inversée, l'absence de gestionnaire permet tout — comme AppKit quand la méthode du délégué n'est pas implémentée.toColumn vaut -1 au PREMIER appel, au moment où la colonne est saisie et avant qu'une destination existe. L'en-tête le dit : refuser à cet instant interdit tout déplacement de cette colonne.

Glisser de lignes

AllowsRowReordering As Boolean
Déplacer une ligne en la glissant à la souris. Le dépôt appelle MoveRow, donc l'animation de déplacement sert ici sans une ligne de plus. Vaut aussi pour NativeOutlineView depuis le 14 septembre 2026, par ses propres méthodes de source — voir sa carte.Comme dans Numbers : la ligne d'origine reste en place et sélectionnée, une ombre — copie des lignes saisies sur une carte à liseré couleur d'accent, avec une ombre portée franche — suit le curseur dans la table, et AppKit trace la ligne d'insertion (style de retour Regular). Les lignes non contiguës sont rapprochées dans l'ombre.L'ombre est une vraie vue posée dans la table, faite des photos prises quand les lignes sont saisies ; l'image de glisser d'AppKit est vidée. Le style Gap, utilisé d'abord, masquait la ligne saisie : la sélection disparaissait et un trou restait vide. Un dépôt proposé sur une ligne est recadré au-dessus.
Event RowsMoved(sources() As Integer, firstRow As Integer)
Levé après un dépôt réussi : les indices d'ORIGINE dans l'ordre croissant, et l'endroit où le bloc a atterri. Une sélection non contiguë en donne plusieurs d'un coup.L'arithmétique du dépôt est le seul endroit délicat. AppKit donne l'indice d'insertion dans le repère d'AVANT le déplacement, et chaque ligne retirée décale d'un cran tout ce qui la suit — avec une sélection multiple, ces décalages se composent. L'algorithme n'est pas déduit mais vérifié : simulé sur les 1757 cas que forment toutes les tailles jusqu'à sept lignes, tous les sous-ensembles de sélection et tous les points de dépôt, comparé à un résultat calculé indépendamment. Zéro écart.
Controls

NativeCollectionView

classe

Une grille d'éléments — NSCollectionView et sa disposition flow. Xojo n'a rien de tel. Chaque élément est un NSCollectionViewItem, normalement chargé d'un nib : ici on lui pose sa vue, loadView n'est alors jamais appelé, et le nib devient inutile. Les éléments sont gardés en cache plutôt que recyclés — compromis assumé, voir les pièges.

Constructeur

Sub Constructor(width As Double = 600, height As Double = 300, itemWidth As Double = 104, itemHeight As Double = 104)

VÉRIFIÉ plutôt que supposé : un NSCollectionViewItem accepte qu'on lui POSE sa vue, et loadView n'est alors jamais appelé. C'est la même ruse que NativeWindowChrome emploie pour ses NSViewController, et elle dispense entièrement de nib.

Méthodes

Sub AddFile(item As FolderItem)
L'icône du Finder rend compte de CET élément précis — dossier, application, document — et non de son type. C'est ce que voit l'utilisateur.
Sub AddItem(title As String, symbolName As String = "")
Function Count() As Integer
Function Handle() As Ptr
La vue à POSER : le NSScrollView, pas la grille — celle-ci est son documentView et se redimensionne toute seule.
Sub Reload()
Sub RemoveAllItems()
Sub SetItemSize(width As Double, height As Double)
Sub SetSpacing(betweenItems As Double, betweenLines As Double)

Propriétés

HorizontalScrolling As Boolean
AllowsMultipleSelection As Boolean

Événements

  • Event SelectionChanged(index As Integer)
Controls

NativePredicateEditor

classe

Le constructeur de règles de macOS — « Nom contient … ET Taille > … » —, le composant même de la fenêtre de recherche du Finder. Xojo n'a ni cette interface ni le prédicat qui en sort. On déclare des champs typés, Build en tire les modèles de ligne, et PredicateFormat rend la forme textuelle à enregistrer.

Constructeur

Sub Constructor(width As Double = 560, height As Double = 180)

L'éditeur GRANDIT avec les règles ajoutées : il vit donc dans un NSScrollView, sans quoi les lignes du bas sortent du cadre.

Méthodes

Sub AddField(keyPath As String, kind As Kinds = Kinds.Text)
Le champ est désigné par son CHEMIN DE CLÉ — « nom », « taille ». C'est ce qui apparaît dans le premier menu de chaque règle, et ce qu'on retrouvera dans le prédicat produit.
Sub Build()
Un modèle de ligne par TYPE, pas par champ : AppKit attend qu'on lui donne toutes les expressions de gauche partageant le même type et les mêmes opérateurs dans un seul NSPredicateEditorRowTemplate.
Sub AddRow()
addRow: LÈVE une NSRangeException à l'intérieur d'AppKit — vérifié — si la ligne racine n'est pas COMPOSÉE. L'éditeur tombe dans cet état dès qu'on lui pose un prédicat simple, et le bouton « ajouter » devient alors une mine. On rétablit donc la racine avant d'ajouter.
Function Handle() As Ptr
La vue à POSER : le NSScrollView, l'éditeur grandissant avec ses règles.
Function PredicateFormat() As String
La forme TEXTUELLE du prédicat — « nom CONTAINS "a" AND taille > 100 ». C'est elle qu'on enregistre, et elle seule qui se relit.
Function RowCount() As Integer
Sub SetPredicateFormat(format As String)
DANGER, et il est réel : predicateWithFormat: lève une NSInvalidArgumentException sur une chaîne mal formée — vérifié —, et une exception Objective-C ne se rattrape PAS depuis Xojo : elle termine le processus. Ne passez ici que des chaînes que vous avez produites vous-même, typiquement relues de PredicateFormat.

Propriétés

NestingMode As NestingModes
RowHeight As Double

Événements

  • Event Changed(predicateFormat As String)

Énumérations

KindsText=0Number=1Date=2YesNo=3
NestingModesSingle=0List=1Compound=2

Contrôles plaçables

Ceux-ci ne se fabriquent pas en code : ils se glissent depuis la bibliothèque et se règlent dans l'inspecteur. Quinze héritent d'un contrôle natif de Xojo, récupèrent à l'ouverture le vrai NSView qu'il a déjà créé, via Ptr(Me.Handle), et y posent ce que Xojo n'expose pas. Les douze autres hébergent : ils descendent de DesktopCanvas et logent un objet de la bibliothèque — la table et l'arbre, et dix contrôles AppKit.

À savoir en posant un de ces contrôles à la main dans un .xojo_window. DesktopImageViewer, DesktopProgressBar et DesktopProgressWheel sont les seuls types à écrire PanelIndex en plus de TabPanelIndex. Absente, elle vaut 0 : le contrôle appartient au panneau zéro et se dessine par-dessus TOUTES les pages, à ses propres coordonnées — ce qui ressemble à un défaut de mise en page sur la page envahie. PanelIndex est le jumeau 0-basé du TabPanelIndex 1-basé. Ces trois types portent également AllowTabStop, et non TabStop.

Contrôles plaçables

NativeButtonControl

classe

Hérite de DesktopButtonNSButton. Bouton Xojo natif enrichi sur place. Glissé depuis la bibliothèque et réglé dans l'inspecteur, comme n'importe quel DesktopButton — mais avec les réglages d'NSButton que Xojo n'expose pas.

Propriétés

ControlSize As NativeButton.ControlSizes
Taille de contrôle AppKit. La police est reposée à la main : DesktopButton en pose déjà une explicite avant Opening, ce qui empêche l'ajustement automatique du corps.
Bordered As Boolean
Bordure du bouton (setBordered:).
ShowsBorderOnlyOnHover As Boolean
La bordure n'apparaît qu'au survol de la souris.
Symbol As String
Le NOM d'un symbole SF — square.and.arrow.up — et non un fichier : le symbole suit la taille du texte, le mode sombre et l'accentuation, ce qu'aucune image posée ne fait. Vide = pas d'icône. Un nom inconnu laisse le bouton tel quel.
ImagePosition As NativeButton.ImagePositions
La place de l'icône, réglable dans l'inspecteur. Leading par défaut.
ImageHugsTitle As Boolean
Icône collée au titre, l'ensemble centré. True par défaut.
Contrôles plaçables

NativeIconButtonControl

classe

Hébergé : loge un NativeButton — un bouton À ICÔNE qu'on pose dans l'IDE. Le seul des contrôles de boutons à héberger plutôt qu'hériter, et ce n'est pas un choix de style : sur un DesktopButton hérité, Xojo EFFACE l'image.

Propriétés

Caption As String
Le titre, comme sur un bouton Xojo.
SymbolName As String
Le NOM d'un symbole SF — square.and.arrow.up. Vide retire l'icône ; un nom inconnu laisse le bouton tel quel. Une image de fichier ou une Picture passent par SetImage et SetPicture.
ImagePosition As NativeButton.ImagePositions
La place de l'icône. Leading par défaut.Above et Below demandent un AUTRE BEZEL : avec Push, le titre est dessiné hors du cadre — mesuré de 32 à 60 points de haut. FlexiblePush et SmallSquare contiennent les deux.
ImageHugsTitle As Boolean
Icône collée au titre, l'ensemble centré. True par défaut. À False, l'icône se plaque contre le bord du cadre.
BezelStyle As NativeButton.BezelStyles
Le dessin du cadre, jusqu'au rond d'aide et à la capsule.
ControlSize As NativeButton.ControlSizes
Le gabarit du système. Le bouton est recentré à chaque changement.

Méthodes

Function Inner() As NativeButton
L'objet hébergé, pour tout ce que l'inspecteur n'expose pas.
Sub SetImage(item As FolderItem) · Sub SetPicture(source As Picture)
Une image du disque ou une Picture Xojo, à la place du symbole.

Événements

Event Pressed()
Contrôles plaçables

NativeCheckBoxControl

classe

Hérite de DesktopCheckBoxNSButton. Case à cocher native, avec le vrai troisième état d'AppKit.

Propriétés

ControlSize As NativeButton.ControlSizes
Taille de contrôle AppKit. La police est reposée à la main : DesktopButton en pose déjà une explicite avant Opening, ce qui empêche l'ajustement automatique du corps.
MixedState As Boolean
État « indéterminé » (allowsMixedState + state = -1) : ni cochée ni décochée. À ne pas confondre avec VisualState de l'inspecteur, qui ne pilote que l'aperçu dans l'éditeur — Value l'écrase à l'exécution.
Contrôles plaçables

NativeRadioButtonControl

classe

Hérite de DesktopRadioButtonNSButton. Bouton radio natif, à taille réglable.

Propriétés

ControlSize As NativeButton.ControlSizes
Taille de contrôle AppKit. La police est reposée à la main : DesktopButton en pose déjà une explicite avant Opening, ce qui empêche l'ajustement automatique du corps.
Contrôles plaçables

NativeTextFieldControl

classe

Hérite de DesktopTextFieldNSTextField. Champ de texte natif portant l'indice de contenu et les drapeaux Writing Tools.

Propriétés

Sub ReapplyNativeSettings()
À appeler après tout changement de Password. Basculer Password fait que Xojo DÉTRUIT la vue et en CRÉE une autre, et Opening n'est pas levé sur la nouvelle : tout ce que cette classe avait posé disparaît sans erreur ni avertissement.Mesuré sur un objet vivant — le pointeur du Handle change à chaque bascule, trois bascules donnant trois vues distinctes ; contentType rendait one-time-code avant et aucun après. Xojo n'offrant aucun moyen d'intercepter l'écriture d'une propriété héritée, la reprise ne peut pas être automatique.Et l'appel doit être DIFFÉRÉ — Timer.CallLater, pas un appel dans la foulée : demander le Handle avant que Xojo ait fini d'installer la vue de remplacement force sa création HORS de son panneau, et le champ se retrouve posé au niveau de la fenêtre.
EchosBullets As Boolean
Les points d'un champ mot de passe. Propriété de la CELLULE, que NSSecureTextField ne relaie pas, et qui n'existe que tant que Password vaut True — hors de là la cellule est une XOJTextFieldCell ordinaire, qui ne répond pas au sélecteur.
ContentType As NativeTextField.ContentTypes
Indice sémantique NSTextContentType : ce que le champ ATTEND. C'est lui qui permet au système de proposer un code reçu par SMS. La table est partagée avec NativeTextField.SymbolFor, pas recopiée.
AllowsWritingTools As Boolean
macOS 15.2.
AllowsWritingToolsAffordance As Boolean
macOS 15.4. Ne vaut que si AllowsWritingTools est vrai.
Contrôles plaçables

NativeTextAreaControl

classe

Hérite de DesktopTextAreaNSTextView. Zone de texte native. Particularité : DesktopTextArea est composite — une NSScrollView qui héberge la vraie NSTextView — et rien ne garantit laquelle des deux Handle rend. La classe le constate par sélecteur au lieu de le supposer.

Propriétés

ContinuousSpellChecking As Boolean
Correction orthographique au fil de la frappe.
AutomaticLinkDetection As Boolean
Ne joue que sur le texte TAPÉ ensuite, pas sur celui déjà présent.
UsesFindBar As Boolean
Barre de recherche de TextEdit (Cmd-F), avec recherche incrémentale.
Contrôles plaçables

NativePopupMenuControl

classe

Hérite de DesktopPopupMenuNSPopUpButton. Menu local natif, avec les deux réglages macOS 15 de NSPopUpButton.

Propriétés

AltersStateOfSelectedItem As Boolean
Coche l'item choisi. Ignoré sur un bouton déroulant.
UsesItemFromMenu As Boolean
Ne vaut que pour un bouton DÉROULANT — DesktopPopupMenu reste du type surgissant. Repose synchronizeTitleAndSelectedItem, sans quoi décocher puis recocher laisse le bouton muet.
Contrôles plaçables

NativeComboBoxControl

classe

Hérite de DesktopComboBoxNSComboBox. Liste déroulante native. NSComboBox.completes n'est volontairement pas repris : Xojo l'expose déjà sous AllowAutoComplete.

Propriétés

VisibleItems As Integer
Lignes montrées avant défilement. Zéro = réglage d'AppKit conservé.
ItemHeight As Double
Hauteur d'une ligne. Zéro = réglage d'AppKit conservé.
ButtonBordered As Boolean
Bordure du bouton fléché.
Contrôles plaçables

NativeSliderControl

classe

Hérite de DesktopSliderNSSlider. Curseur natif avec la valeur neutre de macOS 26.

Propriétés

NeutralValue As Double
macOS 26. Le remplissage part de cette valeur plutôt que du minimum — un égaliseur centré, par exemple.
Contrôles plaçables

NativeGroupBoxControl

classe

Hérite de DesktopGroupBoxNSBox. Boîte de groupe native, dont le titre peut enfin changer de taille.

Propriétés

TitleFontSize As Double
DesktopGroupBox applique Bold/FontSize à son CONTENU, jamais à son propre titre — qui restait à la taille système quel que soit le réglage.
Contrôles plaçables

NativeImageViewerControl

classe

Hérite de DesktopImageViewerNSImageView. Visualiseur d'image natif, en mode modèle.

Propriétés

Template As Boolean
NSImage.isTemplate : recoloration automatique par le système, noir sur clair et blanc sur sombre. Le réglage porte sur l'IMAGE : réaffecter Image ensuite fabrique une nouvelle NSImage et perd le drapeau.
Contrôles plaçables

NativeProgressBarControl

classe

Hérite de DesktopProgressBarNSProgressIndicator. Barre de progression native, avec départ et arrêt d'animation que Xojo n'expose pas.

Méthodes

Sub ReapplyNativeSettings()
À appeler après tout changement d'Indeterminate. La bascule fait que Xojo DÉTRUIT la vue et en crée une autre, et Opening n'est pas levé sur la nouvelle : ControlSize et DisplayedWhenStopped sont perdus sans erreur.Les quinze contrôles plaçables ont été passés au même test, Password sur un champ de texte servant de témoin positif. Enabled, Visible et Width ne recréent la vue sur aucun ; Indeterminate et Password sont les deux seuls cas trouvés.
Sub StartAnimation()
Sans arrêt possible, DisplayedWhenStopped n'aurait aucune occasion de jouer.
Sub StopAnimation()

Propriétés

ControlSize As NativeButton.ControlSizes
Une barre « small » est sensiblement plus fine que la régulière.
DisplayedWhenStopped As Boolean
À faux, l'indicateur disparaît dès qu'il n'anime plus.
Contrôles plaçables

NativeProgressWheelControl

classe

Hérite de DesktopProgressWheelNSProgressIndicator. Roue d'attente native. DisplayedWhenStopped compte surtout ici : une roue laissée affichée à l'arrêt est un artefact visuel, pas une information.

Méthodes

Sub StartAnimation()
Sub StopAnimation()

Propriétés

ControlSize As NativeButton.ControlSizes
DisplayedWhenStopped As Boolean
À faux, la roue s'efface au repos.
Contrôles plaçables

NativeTabPanelControl

classe

Le vrai NSTabView qui dort sous DesktopTabPanel. Vérifié au runtime, pas supposé : la vue posée par Xojo est de classe XOJTabView, lignée XOJTabViewNSTabViewNSView. Le gain principal tient en un mot : Xojo ne sait poser les onglets qu'en haut, AppKit les met aussi à gauche, en bas, à droite — ou nulle part.

Propriétés

TabPosition As TabPositions
macOS 10.12. None, Top, Left, Bottom, Right. La seule que Xojo ne sait pas faire.
BorderType As BorderTypes
N'est respecté que si TabPosition vaut None — l'en-tête est formel, et la mesure des quinze combinaisons va plus loin : la propriété mémorise toujours la valeur posée et se relit fidèlement, mais tabViewType, celui qui pilote le dessin, reste …Bezel dès que la position n'est pas None. Les trois bordures ne se distinguent qu'en position None, où tabViewType prend NoTabsNoBorder, NoTabsLine ou NoTabsBezel.Se relire ne révèle donc PAS que le réglage est inerte. Une interface qui expose BorderType a intérêt à le griser hors de cette position.
ControlSize As NativeButton.ControlSizes
Englobe le SmallTabs de Xojo, qui n'a que deux états : Small en fait autant, avec trois gabarits de plus.
AllowsTruncatedLabels As Boolean · DrawsBackground As Boolean
Le second ne vaut que pour un onglet sans bordure — « only relevant for borderless tab view type ».

Méthodes

Sub SelectNext() · SelectPrevious() · SelectFirst() · SelectLast()
Les quatre actions de navigation d'AppKit, que Xojo n'expose pas : il faut sinon calculer l'indice suivant en gérant les bornes.
Function ContentRect() As Cocoa.NSRect · Function MinimumSize() As Cocoa.NSSize
La zone réellement disponible pour une page, et la taille en dessous de laquelle les onglets ne tiennent plus. Coordonnées AppKit, origine en bas.

Xojo place les enfants, AppKit déplace les onglets. Poser TabPosition sur le côté change la zone de contenu du NSTabView, mais les contrôles posés dedans sont placés par Xojo, à des coordonnées calculées pour des onglets EN HAUT — il ne les repositionne pas. Sur une page calée au pixel près, tout se décale. ContentRect rend la zone réelle pour replacer soi-même.

Ce que Xojo couvre déjà, et qui n'est donc pas repris : la police des libellés, par FontName, FontSize, Bold, Italic et Underline. L'ancienne propriété tabViewType non plus : elle combine position et bordure, et l'en-tête conseille lui-même les deux propriétés séparées.

Un détail qui coûte une compilation : l'IDE écrit Value dans le bloc Begin — l'onglet sélectionné au départ — mais DesktopTabPanel ne l'expose pas à l'exécution. Le membre s'appelle SelectedPanelIndex. Une propriété sérialisée n'est donc pas forcément lisible en code.

Contrôles plaçables

NativeScrollBarControl

classe

Le vrai NSScroller sous DesktopScrollbarXOJScrollerNSScrollerNSControl, vérifié au runtime. Barre héritée ou en surimpression, curseur clair ou sombre, gabarit réduit : quatre réglages qu'AppKit expose et que Xojo passe sous silence.

Propriétés

ScrollerStyle As ScrollerStyles
Legacy occupe toujours sa place ; Overlay se pose par-dessus le contenu et s'efface au repos. Le poser contredit délibérément le réglage global de la personne, que PreferredScrollerStyle permet de lire d'abord.
KnobStyle As KnobStyles
Dark et Light ne valent QUE pour une barre en surimpression : une barre héritée prend les couleurs du système. C'est le réglage qui rend une barre lisible par-dessus un fond sombre peint à la main. Mesuré en rendant la barre dans un bitmap et en comparant les octets — la propriété, elle, se relit toujours fidèlement et n'apprend rien : en style hérité les trois valeurs donnent une image identique pixel pour pixel.En surimpression, Dark est lui aussi identique à Default : l'énumération a trois valeurs pour deux rendus. Une interface qui expose KnobStyle a intérêt à le griser en style hérité.
ControlSize As NativeButton.ControlSizes
NSScroller étant un NSControl, il accepte les gabarits : une barre mini est sensiblement plus fine.
KnobProportion As Double
La part de la glissière qu'occupe le curseur, de 0 à 1. Xojo écrit lui aussi cette propriété — c'est ainsi qu'il dimensionne le curseur d'après PageStep : une valeur posée à la main ne tient que jusqu'au prochain rafraîchissement.

Méthodes partagées

Shared Function WidthForControlSize(size As NativeButton.ControlSizes, style As ScrollerStyles) As Double
La largeur qu'AppKit donnerait à une telle barre. À employer pour dimensionner l'ancre plutôt que de coder 16 en dur : la valeur change avec le style.
Shared Function PreferredScrollerStyle() As ScrollerStyles · OverlayScrollersSupported() As Boolean
Le choix de la personne dans Réglages Système, et la question que pose l'en-tête : la surimpression est-elle possible ici ? Pour adapter une interface, pas pour garder un appel.

Pas de PanelIndex sur ce type : DesktopImageViewer, DesktopProgressBar et DesktopProgressWheel restent les seuls à l'écrire. Relevé sur le ViewBehavior qu'un IDE a écrit pour une sous-classe existante de ce même contrôle, pas déduit.

Contrôles plaçables

NativeLabelControl

classe

Le vrai NSTextField sous DesktopLabelXOJStaticTextNSTextFieldNSControl, lu par object_getClass sur un libellé vivant. Xojo en donne le texte, la police et la couleur ; il ne donne rien de ce qui décide COMMENT le texte est coupé quand il ne tient pas.

Propriétés

LineBreakMode As LineBreakModes
Le manque le plus criant. Xojo laisse couper à la fin et rien d'autre ; AppKit tronque en tête (…wxyz), au milieu (ab…yz), à la fin (abcd…), rogne sans points de suspension, ou renvoie à la ligne au mot ou au caractère. macOS 10.10, sur NSControl, qui transmet à sa cellule.
MaximumNumberOfLines As Integer
macOS 10.11. Zéro veut dire « pas de limite », et c'est le défaut.Piège écrit dans l'en-tête : au-delà de ce nombre le texte est ROGNÉ, et seulement tronqué avec des points de suspension si TruncatesLastVisibleLine est posé. Sa valeur change aussi ce que rend FittingSize.
TruncatesLastVisibleLine As Boolean
Propriété de la CELLULE, que NSTextField ne relaie pas. N'est honorée que sous WordWrapping ou CharWrapping — l'en-tête est formel. Réglée sous un autre mode, elle ne fait rien et se relit pourtant fidèlement.Même mécanique que la bordure d'onglet et le style de curseur : une interface qui l'expose a intérêt à la griser hors des deux modes de renvoi à la ligne.
AllowsDefaultTighteningForTruncation As Boolean
macOS 10.11. Resserre légèrement l'espace entre les caractères avant de renoncer et de tronquer — ce qui évite un sur un mot qui dépassait de deux points.
AllowsExpansionToolTips As Boolean
macOS 10.8. La bulle qui montre le texte entier au survol quand il est coupé, celle du Finder sur un nom de fichier trop long. Le système ne la fabrique que si le texte est effectivement tronqué.
Bordered As Boolean
Un filet d'un point autour du libellé. Xojo n'a que Transparent, qui ne joue que sur le fond.
DrawsBackground As Boolean
Commande le fond. BackgroundColor ne peint rien sans lui.Ces notes ont d'abord supposé un recouvrement avec le Transparent de Xojo. C'est faux, et mesuré : sur un libellé neuf, Transparent vaut False quand drawsBackground vaut False lui aussi — si les deux se commandaient, un libellé non transparent peindrait son fond. Les deux drapeaux sont indépendants.
BackgroundColor As Color
La couleur du fond. Conversion Xojo → Cocoa comprise : chez Xojo, Alpha vaut 0 pour opaque et 255 pour transparent, l'inverse de la convention Cocoa.

Méthodes

Sub SetViewOrigin(x As Double, y As Double)
Repose l'origine du cadre en coordonnées AppKit — donc y compté depuis le BAS de la vue parente. Écrire Width à l'exécution sur un enfant de DesktopPagePanel déplace la vue, et Xojo ne s'en aperçoit pas : il continue d'annoncer les Left et Top d'origine.Mesuré : avant, Xojo 230, 100 · 460 × 90 et AppKit 28, 589 · 464 × 90, d'accord à l'encart près ; après Width = 700, Xojo dit toujours 230, 100 quand AppKit est passé à 3, 641. La parade tient en trois gestes : relever ViewFrame, écrire la taille, reposer SetViewOrigin.
Function ViewFrame() As Cocoa.NSRect
Le cadre RÉEL de la vue, à comparer aux Left, Top, Width et Height que Xojo croit avoir posés. Si les deux divergent, quelque chose a déplacé la vue dans le dos de l'un des deux, et aucune capture d'écran ne le dira à sa place.y se compte depuis le bas chez AppKit et depuis le haut chez Xojo : un écart sur y n'est donc pas forcément une anomalie, un écart sur x ou sur la largeur en est une.
Function FittingSize() As Cocoa.NSSize
La taille qu'il faudrait pour tout montrer, SANS toucher au cadre.sizeToFit n'est délibérément pas exposé : il redimensionne la vue dans le dos de Xojo, qui garde ses propres Width et Height et les rétablit au premier rafraîchissement. Mesurer, puis écrire Me.Width.
Function SingleLineMode() As Boolean
Diagnostic, en lecture seule : la valeur réelle de usesSingleLineMode, pendant AppKit de ce que Xojo appelle Multiline. Le lire dit lequel des deux commande, au lieu de supposer une correspondance.
Function ReadsDrawsBackground() As Boolean
Même usage pour drawsBackground face au Transparent de Xojo.
Contrôles plaçables

NativeTableViewControl

classe

Une NativeTableView qu'on glisse depuis la barre d'outils de l'IDE, comme n'importe quel contrôle : hauteur de ligne, en-tête, sélection multiple, colonnes déplaçables et le reste se règlent dans l'Inspecteur, et les événements s'implémentent directement dessus.

Il héberge au lieu d'hériter, et c'est forcé. Quinze contrôles plaçables héritent d'un contrôle Xojo dont la vue EST déjà le contrôle AppKit voulu. Pour une table c'est impossible : le balayage des 82 classes de XojoFramework a montré que XOJListboxView descend d'un NSView nu — DesktopListBox n'est pas une NSTableView, Xojo y dessine lui-même. Ce contrôle descend donc de DesktopCanvas et loge une table dedans. L'hébergement se fait dans Paint, seul moment où le contrôle est réellement à l'écran : demander son Handle plus tôt créerait sa vue HORS de son panneau, donc visible sur toutes les pages. La table, elle, existe bien avant — elle fabrique ses propres vues sans hôte — ce qui permet de la remplir dès l'Opening de la fenêtre.

Méthodes

Function Table() As NativeTableView
La table elle-même, pour tout ce que ce contrôle ne relaie pas.NativeTableView compte une quarantaine de méthodes publiques ; les relayer toutes ferait autant de code à maintenir en double, qui divergerait au premier ajout. Sont relayées celles dont on se sert à chaque table — colonnes, lignes, cellules, sélection — et le reste passe par Table, sans détour ni perte.
Sub AddColumn(…)
Sub AddRow(ParamArray cells() As String)
Sub SetCell(…)
Function CellAt(…) As String
Sub RemoveAllRows()
Sub Reload()
Function RowCount() As Integer
Function ColumnCount() As Integer
Sub SelectRow(row As Integer)
SelectedRow As Integer
Ce qui est relayé. AddRow passe par AddRowArray : un ParamArray ne se transmet pas d'une méthode à l'autre, et ce contrôle n'hérite pas de la table — il l'héberge.
Event SelectionChanged · CellChanged · RowDoubleClicked · SortChanged · RowsMoved
Les événements de la table, relevés par le contrôle : celui qui le pose les implémente sans savoir qu'il y a une table dedans.
Contrôles plaçables

NativeOutlineViewControl

classe

Une NativeOutlineView qu'on glisse depuis la barre d'outils de l'IDE. Hérite de NativeTableViewControl ; MakeTable loge l'arbre et relève en plus ses événements nœud.

Un arbre est une table qui indente

Tout ce qui le sépare de son parent tient dans MakeTable : il loge un NativeOutlineView au lieu d'un NativeTableView, et relève ses trois événements nœud. Le reste est hérité : l'hébergement différé dans Paint, les propriétés de l'Inspecteur, les événements de la table. Un nœud est un NativeOutlineNode, plus un numéro de ligne : insérer, retirer et déplacer s'animent.

Méthodes

Function Tree() As NativeOutlineView
La même instance que Table, mais typée : c'est par elle que passe ce qui n'est pas relayé — Tree.SetNodeIcon, Tree.NodeCell, Tree.ExpandNode.
Function AddNode(parent As NativeOutlineNode, ParamArray cells() As String) As NativeOutlineNode
Function InsertNode(parent, index, cells(), animation = SlideDown) As NativeOutlineNode
Function AddNodeAnimated(parent, cells(), animation = FadeSlideDown) As NativeOutlineNode
Sub RemoveNode(node, animation = SlideUp)
Function MoveNode(node, newParent, index) As Boolean
Function AddFolder(parent, item As FolderItem, depth As Integer = 3) As NativeOutlineNode
Function ParentOf(node) · ChildCount(parent) · ChildAt(parent, index) · IndexOf(node)
Function SelectedNode() · Sub SelectNode(node) · Sub ExpandAll() · Sub CollapseAll()
Ce qui est relayé : construire, retirer, déplacer, parcourir, sélectionner. Nil comme parent désigne la racine.
Event NodeSelectionChanged · NodeCellChanged · NodeDoubleClicked · NodesMoved
Relevés de l'arbre, avec le nœud.Les événements de la table — SelectionChanged, CellChanged, RowDoubleClicked — coexistent et donnent une ligne de stockage. Préférer ceux-ci : une ligne change dès qu'on insère ou déplace.
Contrôles plaçables

NativeSwitchControl

classe

Un NSSwitch qu'on glisse depuis la barre d'outils de l'IDE. Hébergé comme la table : il descend de DesktopCanvas et loge une NativeSwitch.

Monté par Center, comme dans MainWindow : un interrupteur a une taille intrinsèque, l'étirer n'aurait aucun sens. Il est recentré à chaque changement de gabarit.

Méthodes

Function Inner() As NativeSwitch
L'objet hébergé, pour ce qui n'est pas relayé.Nommé Inner dans les dix contrôles hébergés : un nom tiré de la classe aurait donné SearchField ou SegmentedControl, des noms de classes de l'ancienne API de Xojo qui masqueraient le type aux sites d'appel.
Value As Boolean
ControlSize As NativeButton.ControlSizes
Réglables dans l'Inspecteur.Poser Value par le code ne lève pas ValueChanged : AppKit n'envoie son action qu'au geste de l'utilisateur.
Event ValueChanged(value As Boolean)
Le Changed de la classe hébergée, sous le nom de l'API 2 de Xojo.
Contrôles plaçables

NativeStepperControl

classe

Un NSStepper — les deux petites flèches — qu'on pose dans l'IDE. Ce que DesktopUpDownArrows ne fait pas : un pas réglable, le bouclage au-delà des bornes, la répétition au clic maintenu.

Monté par Center. Les bornes et le pas se changent après la construction grâce à NativeStepper.SetRange, ajoutée pour ce contrôle : la classe hébergée ne les posait qu'à sa création.

Méthodes

Function Inner() As NativeStepper
L'objet hébergé.
Value · MinimumValue · MaximumValue · Increment As Double
Autorepeat · ValueWraps As Boolean
ControlSize As NativeButton.ControlSizes
Réglables dans l'Inspecteur. ValueWraps fait repartir la valeur du minimum au-delà du maximum.
Event ValueChanged(value As Double)
Le Changed de la classe hébergée.
Contrôles plaçables

NativeSegmentedButtonControl

classe

Un NSSegmentedControl qu'on pose dans l'IDE. Son nom est celui de Xojo, DesktopSegmentedButton : NativeSegmentedControlControl se lirait mal.

Monté par Fill, et non par Center comme dans MainWindow. L'en-tête d'AppKit dit que la répartition distribue l'espace disponible : Fill, valeur par défaut, étire les segments pour le remplir, Fit laisse le reste vide. Centré à sa taille idéale, le contrôle n'aurait aucun espace à répartir ; monté par Fill, la largeur donnée dans l'IDE est respectée.

Méthodes

Function Inner() As NativeSegmentedControl
L'objet hébergé.
Labels As String
Les libellés en un seul champ, séparés par des points-virgules : « Jour;Semaine;Mois ».Changeables après la construction grâce à NativeSegmentedControl.SetLabels, ajoutée pour ce contrôle.
SelectedIndex As Integer
Style As NativeSegmentedControl.Styles
TrackingMode As NativeSegmentedControl.TrackingModes
Distribution As NativeSegmentedControl.Distributions
BorderShape As NativeControlHost.BorderShapes
ControlSize As NativeButton.ControlSizes
Réglables dans l'Inspecteur.BorderShape n'agit qu'à partir de macOS 26.
Function SegmentCount() As Integer
Function IsSelected(index As Integer) As Boolean
Sub SetSelected(index As Integer, selected As Boolean)
Sub SetSymbol(index As Integer, symbolName As String, accessibilityDescription As String = "")
Sub SetWidth(index As Integer, width As Double)
Relayées. En suivi SelectAny, plusieurs segments peuvent être choisis à la fois.
Event SelectionChanged(index As Integer)
Le Changed de la classe hébergée.
Contrôles plaçables

NativeLevelIndicatorControl

classe

Un NSLevelIndicator qu'on pose dans l'IDE : jauge de capacité continue ou discrète, indicateur de pertinence, ou étoiles de notation.

Monté par Fill : la course suit la largeur du contrôle. Le style et les bornes se changent après la construction grâce à NativeLevelIndicator.SetStyle et SetRange, ajoutées pour ce contrôle. SetRange repousse les seuils des bandes de couleur au-delà du nouveau maximum : sans cela, un maximum relevé les ferait retomber dans la course.

Méthodes

Function Inner() As NativeLevelIndicator
L'objet hébergé.
Style As NativeLevelIndicator.Styles
Value · MinimumValue · MaximumValue As Double
Editable As Boolean
Réglables dans l'Inspecteur. Éditable, l'indicateur se règle au clic : c'est ce qui fait d'un Rating une notation.
WarningValue · CriticalValue As Double
InvertedThresholds As Boolean
TickMarks · MajorTickMarks As Integer
Deux seuils à zéro rendent l'apparence par défaut d'AppKit. InvertedThresholds met l'alerte en bas : une batterie plutôt qu'un disque.
Event ValueChanged(value As Double)
Le Changed de la classe hébergée.
Contrôles plaçables

NativeSearchFieldControl

classe

Un NSSearchField qu'on pose dans l'IDE : loupe, croix d'effacement, menu des recherches récentes.

LiveSearch ne reprend pas le défaut d'AppKit. L'en-tête décrit trois comportements : par défaut, une action à chaque frappe « après un temps suffisant pour ne pas gêner la saisie » ; avec sendsWholeSearchString, à Retour ou au clic sur la loupe seulement. Ce contrôle propose deux choix nets : l'envoi immédiat, ou la validation. Monté par Fill.

Méthodes

Function Inner() As NativeSearchField
L'objet hébergé.
Text · Placeholder As String
LiveSearch As Boolean
MaximumRecents As Integer
Réglables dans l'Inspecteur.MaximumRecents à zéro retire le modèle de menu — et l'en-tête le dit, sans modèle les recherches récentes ne sont plus suivies. La classe hébergée savait le poser, pas l'enlever.
Function RecentSearches() As String()
Relayée. SetPlaceholders ne l'est pas : un ParamArray ne se transmet pas d'une méthode à l'autre ; elle reste accessible par Inner.
Event TextChanged(text As String)
Le Changed de la classe hébergée, sous le nom de l'API 2 de Xojo.
Contrôles plaçables

NativeColorWellControl

classe

Un NSColorWell qu'on pose dans l'IDE. Depuis macOS 13, trois présentations : Standard ouvre le panneau des couleurs du système, Minimal et Expanded un sélecteur en popover.

La valeur est un instantané sRGB : un Color de Xojo fait trois octets et ne porte ni espace colorimétrique ni exposition. Monté par Fill, comme dans MainWindow.

Méthodes

Function Inner() As NativeColorWell
L'objet hébergé.
Value As Color
Style As NativeColorWell.Styles
Réglables dans l'Inspecteur.
MaximumLinearExposure As Double
macOS 26. L'en-tête d'AppKit : toute valeur sous 1 est ignorée, et c'est à partir de 2 que la couleur choisie peut porter une exposition linéaire.
Event ValueChanged(value As Color)
Le Changed de la classe hébergée.
Contrôles plaçables

NativeDatePickerControl

classe

Un NSDatePicker qu'on pose dans l'IDE. Ce que DesktopDateTimePicker ne fait pas : le calendrier avec son horloge, la sélection d'une plage, le choix fin des éléments affichés.

Monté par Center, et recentré à chaque changement de style ou d'éléments : le calendrier et le champ texte n'ont pas la même taille. MainWindow montait le calendrier par Fill ; Center le garde à sa taille propre, sans avoir à deviner la hauteur du contrôle.

Méthodes

Function Inner() As NativeDatePicker
L'objet hébergé.
Style As NativeDatePicker.Styles
Mode As NativeDatePicker.Modes
DateElements As NativeDatePicker.DateElements
TimeElements As NativeDatePicker.TimeElements
Bezeled · Bordered As Boolean
Réglables dans l'Inspecteur.
Value As DateTime
Duration As Double
Sub SetRange(minimum As DateTime, maximum As DateTime)
Par le code seulement : un DateTime ne se règle pas dans l'Inspecteur, et le contrôle part de la date du jour.Duration est la longueur de la plage en secondes, en mode DateRange.
Event ValueChanged(value As DateTime, duration As Double)
Le Changed de la classe hébergée.
Contrôles plaçables

NativeTokenFieldControl

classe

Un NSTokenField — le champ à jetons du « À : » de Mail — qu'on pose dans l'IDE. Hébergé : aucune classe de Xojo n'est adossée à NSTokenField.

Deux listes dans l'Inspecteur, séparées par des points-virgules : TokenList, les jetons de départ, et Completions, la liste où puise la complétion. Ce point-virgule est un séparateur de saisie, pas le caractère de tokenisation, qui se règle à part. Standard vaut Rounded : l'en-tête d'AppKit le dit de NSTokenStyleDefault, et ajoute que cela pourrait changer. Monté par Fill : une hauteur de deux lignes laisse les jetons passer à la ligne.

Méthodes

Function Inner() As NativeTokenField
L'objet hébergé.
TokenList · Placeholder · Completions As String
Style As NativeTokenField.Styles
TokenizingCharacter As String
Réglables dans l'Inspecteur.TokenList relu rend les jetons validés, recollés par des points-virgules. TokenizingCharacter vide laisse la virgule d'AppKit.
Function Tokens() As String()
Sub SetTokens(values() As String)
Les jetons tels quels. Le texte en cours de frappe n'en fait pas encore partie : il le devient au caractère de tokenisation, à Retour ou à la perte du focus.Un tableau et non un ParamArray, qui ne se transmettrait pas jusqu'à la classe hébergée. Un jeton contenant un point-virgule ne passe que par ici.
Event TokensChanged(tokens() As String)
Le Changed de la classe hébergée.
Contrôles plaçables

NativePathBarControl

classe

Un NSPathControl — la barre de chemin du Finder — qu'on pose dans l'IDE. Hébergé : aucune classe de Xojo n'y est adossée. NativePathControlControl se lirait mal, et Xojo n'a aucun contrôle dont reprendre le nom.

Cliquer ne navigue pas. PathSelected rapporte le composant cliqué, lu pendant l'envoi de l'action — clickedPathItem n'est valide qu'à ce moment —, et le chemin affiché ne change pas : c'est à l'appelant de le poser. Un fichier déposé, ou choisi dans le panneau du style PopUp, lève aussi PathSelected ; l'en-tête précise qu'alors clickedPathItem vaut nil, et la classe hébergée se replie sur l'URL du contrôle.

Méthodes

Function Inner() As NativePathControl
L'objet hébergé.
Path · Placeholder · AllowedTypes As String
Style As NativePathControl.Styles
Editable As Boolean
Réglables dans l'Inspecteur.Deux styles : NavigationBar, la valeur 1, est dépréciée depuis macOS 10.7. AppKit rend la barre éditable par défaut ; ce contrôle part de False. Et une liste de types vide n'autorise rien pour l'en-tête — c'est nil qui autorise tout, et c'est ce que pose un champ vide.
Value As FolderItem
Par le code seulement : un FolderItem ne se règle pas dans l'Inspecteur.
Event PathSelected(item As FolderItem, path As String)
Event PathDoubleClicked(item As FolderItem, path As String)
Les deux événements de la classe hébergée.DoubleClicked est déjà un événement de DesktopCanvas, avec des coordonnées : celui de la barre prend donc un autre nom.
Contrôles plaçables

NativeComboButtonControl

classe

Un NSComboButton (macOS 13) — une action principale et un menu — qu'on pose dans l'IDE. Hébergé : aucune classe de Xojo n'y est adossée. DesktopBevelButton porte bien un menu, mais la sonde a lu sa vue : XOJBevelButton < NSView, que Xojo dessine lui-même.

Split ou Unified. En Split, le titre lève Pressed et la flèche ouvre le menu. En Unified, un seul segment : l'en-tête d'AppKit dit que, l'action étant posée, le clic la déclenche et le menu n'apparaît qu'à l'appui maintenu. Monté par Center, et recentré à chaque changement de titre, de symbole ou de gabarit. Avant macOS 13, rien n'est posé, sans erreur.

Méthodes

Function Inner() As NativeComboButton
L'objet hébergé.
Caption · Items · SymbolName As String
Style As NativeComboButton.Styles
ControlSize As NativeButton.ControlSizes
Réglables dans l'Inspecteur.Items tient en un champ, séparé par des points-virgules ; le changer reconstruit le menu en entier par NativeComboButton.RemoveAllItems, ajoutée pour ce contrôle. Caption et non Title : c'est le nom de l'API 2 de Xojo.
Function ItemCount() As Integer
Le nombre d'éléments du menu.
Event Pressed()
Event MenuItemSelected(index As Integer, title As String)
Chaque élément du menu porte sa propre cible ; son tag est son rang, et c'est lui que rapporte MenuItemSelected.

Surfaces

Ce qui se dessine derrière le contenu, par-dessus la fenêtre, ou à côté.

Surfaces

NativePopover

classe

NSPopover : la bulle ancrée à un contrôle, avec sa flèche. Sa vue de contenu est inverséey compte depuis le haut, comme partout ailleurs dans la bibliothèque.

Constructeur

Sub Constructor(width As Double = 260, height As Double = 160)

Un popover EXIGE un NSViewController. Pas besoin d'en sous-classer un : il suffit d'un NSViewController nu à qui l'on pose une vue avec setView:, ce qui empêche loadView d'être appelé.

Méthodes

Sub AddView(view As Ptr, x As Double, y As Double, width As Double, height As Double)
y compte depuis le HAUT : la vue de contenu est inversée exprès.
Sub Close()
Function ContentView() As Ptr
La vue où loger le contenu. Inversée : y depuis le haut.
Function Handle() As Ptr
Sub SetContentSize(width As Double, height As Double)
Redimensionne la bulle ET sa vue de contenu : les deux doivent suivre, sinon le contenu se retrouve rogné ou flottant.
Sub SetFullSizeContent(fullSize As Boolean)
macOS 14+ : le contenu occupe aussi la zone de la flèche. Sans effet en dessous.
Sub Show(anchor As DesktopUIControl, edge As Edges = Edges.MinY)
Ancre la bulle sur un contrôle Xojo : sa vue sert de vue de positionnement, ses bounds de rectangle d'ancrage.

Propriétés

Animates As Boolean
Behavior As Behaviors
IsShown As Boolean lecture seule

Événements

  • Event DidClose()
  • Event DidShow()
  • Event WillClose()

Énumérations

BehaviorsApplicationDefined=0Transient=1Semitransient=2
EdgesMinX=0MinY=1MaxX=2MaxY=3
Surfaces

NativeAlert

classe

NSAlert. Deux choses que MessageDialog ne sait pas faire : loger une vue à soi dans l'alerte, et proposer « Ne plus me demander ».

Constructeur

Sub Constructor(messageText As String, informativeText As String = "")

Méthodes

Function Handle() As Ptr
Function AddButton(title As String) As Integer
Renvoie l'indice du bouton, 0 pour le premier ajouté. ATTENTION : c'est l'ordre d'AJOUT, pas l'ordre à l'écran — le premier ajouté est le bouton par défaut, donc celui de DROITE.Sans aucun appel, NSAlert pose un unique bouton « OK ».
Function RunModal() As Integer
Renvoie l'indice 0-basé du bouton, dans l'ordre d'ajout ; -1 si l'alerte n'a pas pu être construite.Alerte MODALE à l'application, et donc bloquante : l'appel ne revient qu'au clic. Pour la forme attachée à une fenêtre, voir RunSheet.
Sub RunSheet(parent As DesktopWindow)
Présentation en TIROIR, attachée à la fenêtre — la forme correcte sur macOS pour une question qui porte sur un document.C'est asynchrone : RunSheet revient immédiatement et l'événement Completed arrive plus tard. Deux conséquences, et les deux sont des pièges : 1. le bloc ET son delegate sont rangés dans des propriétés, jamais dans des locales ; 2. l'instance de NativeAlert doit survivre jusqu'au rappel — donc une propriété de la fenêtre, jamais un Var dans le gestionnaire du clic.
Sub SetAccessoryView(view As Ptr, width As Double = 0, height As Double = 0)
N'importe quelle NSView — donc le Handle de n'importe quel contrôle. Si une taille est fournie, elle est appliquée avant : NSAlert dimensionne son panneau d'après le cadre de la vue, sans le renégocier.
Sub SetCancelButton(index As Integer)
Échap déclenche ce bouton. AppKit le fait déjà tout seul pour un bouton intitulé « Annuler » ou « Cancel » ; à préciser dès que le libellé sort de ces deux mots.
Sub SetDefaultButton(index As Integer)
Déplace la touche Retour. Indispensable avec un bouton destructeur : les règles d'Apple veulent que l'action irréversible ne soit JAMAIS celle qu'on déclenche par réflexe, or AddButton fait du premier ajouté le bouton par défaut. On retire donc l'équivalent clavier à tous les autres.
Sub SetDestructiveButton(index As Integer, destructive As Boolean = True)
NSAlert lui-même n'a pas de notion de « destructeur » : ce sont ses BOUTONS qui en ont une, puisque buttons est un tableau de NSButton. C'est ainsi que le Finder obtient son « Supprimer » rouge.hasDestructiveAction date de macOS 11 ; en dessous, l'appel est sans effet et le bouton reste gris.
Sub SetHelp(shown As Boolean, anchor As String = "")
Sub SetSuppression(shown As Boolean, title As String = "")
La case « Ne plus me demander ». À l'application de retenir le choix : AppKit ne fait que l'afficher et rapporter son état.
Sub SetSymbol(symbolName As String, accessibilityDescription As String = "")
Remplace l'icône de l'application par un symbole SF. Passer "" la rétablit.

Propriétés

InformativeText As String
MessageText As String
Style As Styles
Suppressed As Boolean lecture seule
Valide seulement après RunModal.

Événements

  • Event Completed(buttonIndex As Integer)
  • Event HelpRequested() As Boolean

Delegate

  • Delegate Sub SheetHandler(response As Integer)

Énumérations

StylesWarning=0Informational=1Critical=2
Surfaces

NativeGlassEffectView

classe

NSGlassEffectView (macOS 26) : le Liquid Glass. L'en-tête ne garantit que le contentView — les sous-vues quelconques n'ont pas de z-order défini par rapport à l'effet.

Constructeur

Sub Constructor(width As Double = 200, height As Double = 120, style As Styles = Styles.Regular)

Handle rend Nil sous macOS 26 ; à l'appelant de retomber sur autre chose.

Méthodes

Function Available() As Boolean
Shared Function InteractiveSupported() As Boolean
Pour ADAPTER l'interface : Interactive est déjà sans effet en dessous de macOS 27, où la vue existe sans connaître ce réglage.
Function Handle() As Ptr
Sub SetContentView(view As Ptr)
Sub SetTint(useTint As Boolean, tint As Color = &c000000)
Passer False remet tintColor à Nil : le verre reprend sa teinte neutre.

Propriétés

CornerRadius As Double
Interactive As Boolean
macOS 27, effectIsInteractive. L'en-tête : à activer pour un verre qui sert de fond ou de conteneur à des contrôles — il répond alors au survol et au clic. Défaut NO : un verre qui porte des boutons reste statique tant qu'on ne le demande pas.
Style As Styles

Énumérations

StylesRegular=0Clear=1
Surfaces

NativeGlassEffectContainerView

classe

NSGlassEffectContainerView (macOS 26) — classe distincte de NativeGlassEffectView : elle ne dessine pas une vitre mais en regroupe plusieurs. L'en-tête annonce trois effets : elle remonte le z-order des descendantes de contentView, fusionne celles qui sont assez semblables et assez proches, et les traite par lot pour la performance.

Constructeur

Sub Constructor(width As Double = 200, height As Double = 120)

Handle rend Nil sous macOS 26 ; à l'appelant de retomber sur autre chose.

Méthodes

Function Available() As Boolean
Function Handle() As Ptr
Sub SetContentView(view As Ptr)
Les vitres à fusionner vont EN DESCENDANCE de cette vue, pas directement dans le conteneur.

Propriétés

Spacing As Double
Proximité à partir de laquelle les vitres fusionnent. Par défaut zéro : traitement par lot, sans fusion visible ni distorsion des vues simplement voisines.
Surfaces

NativeBackgroundExtensionView

classe

macOS 26. Elle prolonge son contenu jusqu'à ses propres limites. L'usage prévu est précis : une vue qui déborde de la zone sûre, sous la barre de titre, la barre latérale ou l'inspecteur. Le contenu, lui, reste dans la zone sûre — ce sont ses bords que le système étire pour remplir le reste. Available() interroge la classe, pas le numéro de version ; Handle rend Nil avant macOS 26.

Constructeur

Sub Constructor(width As Double = 400, height As Double = 240)

L'usage prévu est précis — poser une vue qui déborde de la zone sûre, sous la barre de titre, la barre latérale ou l'inspecteur. Le contenu, lui, reste DANS la zone sûre ; ce sont ses bords que le système étire et floute pour remplir le reste. On obtient donc une image qui semble passer sous la barre d'outils sans qu'elle y soit réellement tronquée.

Handle rend Nil avant macOS 26 : à l'appelant de retomber sur autre chose, typiquement la vue de contenu posée seule.

Méthodes

Function Available() As Boolean
Vrai seulement si la classe existe VRAIMENT dans le système en cours. On interroge la classe, pas le numéro de version : un sélecteur présent est une preuve, un numéro de version une supposition.
Function Handle() As Ptr
Sub SetContentView(view As Ptr)
La vue à prolonger. Elle devient sous-vue de l'extension et, par défaut, est placée dans la zone sûre — voir AutomaticPlacement.
Function ContentView() As Ptr

Propriétés

AutomaticPlacement As Boolean
À True — le défaut —, le système place lui-même la vue de contenu dans la zone sûre. À False, c'est à l'appelant de poser le cadre ou les contraintes, et l'effet d'extension remplit ce qui reste autour.
Surfaces

NativeMenu

classe

NSMenu avec tout ce que macOS 14 lui a ajouté : en-têtes de section, symboles SF, sous-titres (14.4), pastilles typéesUpdates, NewItems, Alerts portent un libellé localisé par le système, là où la pastille simple n'affiche que le nombre — modes de sélection, et les menus palette, la rangée de pastilles colorées des étiquettes du Finder.

Constructeur

Sub Constructor(title As String = "")

Méthodes

Function AddItem(title As String, symbolName As String = "", subtitle As String = "") As Integer
Rend l'indice de l'item, qui sert de tag et revient dans l'événement Chosen.
Function AddSectionHeader(title As String) As Integer
macOS 14 : un vrai en-tête de section, non sélectionnable et dessiné comme tel. En dessous, on retombe sur un item désactivé — pas identique, mais lisible, et sans test à écrire chez l'appelant.
Sub AddSeparator()
Function AddSubmenu(title As String, submenu As NativeMenu, symbolName As String = "") As Integer
Le sous-menu est RETENU par l'item ; garder l'objet Xojo vivant reste à la charge de l'appelant, sinon son destructeur relâchera le NSMenu sous l'item.
Function AddColorPalette(title As String, colors() As Color, titles() As String, checkSize As Double = 10) As Integer
macOS 14 : la rangée de pastilles colorées, comme les tags du Finder.Deux contraintes que l'en-tête énonce et qu'on ne peut pas contourner : un menu palette doit être le SOUS-MENU d'un item d'un menu ordinaire, et il ne peut être ni déroulé par PopUp ni attaché à un menu surgissant. D'où la signature : on donne le titre de l'item porteur, pas le menu lui-même. Le gestionnaire de sélection de la fabrique est facultatif : on passe Nil et on lit SelectedIndexes sur le sous-menu — ce qui évite d'avoir à fabriquer un bloc Objective-C.
Function PaletteSelection(index As Integer) As Integer()
Indices sélectionnés dans la palette portée par l'item donné.
Function Handle() As Ptr
Function PopUp(anchor As DesktopUIControl, dx As Double = 0, dy As Double = 0) As Boolean
Déroule le menu sous un contrôle Xojo et rend True si un item a été choisi. L'appel est SYNCHRONE : il ne revient qu'à la fermeture du menu, ce qui permet de lire la sélection juste après.Coordonnées AppKit, origine EN BAS : (0,0) est le coin bas-gauche de l'ancre, et le menu s'ouvre donc juste en dessous.
Sub RemoveAll()
Function SelectedIndexes() As Integer()
macOS 14, et seulement en mode de sélection SelectOne ou SelectAny : les items cochés d'un même groupe de sélection.
Sub SetBadge(index As Integer, count As Integer, kind As Badges = Badges.Plain)
macOS 14. Les trois types nommés portent un libellé localisé par le système — « 3 mises à jour », « 2 nouveaux éléments » — là où Plain n'affiche que le nombre. Sans effet en dessous de 14.
Sub SetBadgeText(index As Integer, text As String)
Sub SetEnabled(index As Integer, enabled As Boolean)
Sub SetIndent(index As Integer, level As Integer)
Sub SetImageVisibility(index As Integer, visibility As ImageVisibilities)
La même chose pour UN item.
Shared Function ImageVisibilitySupported() As Boolean
Pour ADAPTER l'interface : sous un système antérieur, les images s'affichent de toute façon.
Sub SetState(index As Integer, state As Integer)
NSControlStateValue : Off = 0, On = 1, Mixed = -1.
Sub SetSymbol(index As Integer, symbolName As String)
Sub AttachTo(control As DesktopUIControl) · AttachTo(view As Ptr)
Fait de ce menu le menu CONTEXTUEL. La surcharge sur une vue est nécessaire dès qu'une vue est POSÉE dans le contrôle d'ancrage : le clic droit atteint la vue du dessus, pas celle du contrôle Xojo.
Shared Sub ShowForSelection(control As DesktopUIControl) · ShowForSelection(view As Ptr)
macOS 15. Déroule le menu contextuel de la vue là où se trouve la sélection — ce que fait la touche du système, Ctrl-Retour par défaut. Il n'y a rien à écrire pour que cette touche marche : l'en-tête est catégorique, « Most applications should not override this method ». Le système remonte la chaîne des répondants jusqu'à NSApplication, qui envoie showContextMenuForSelection:, et l'implémentation par défaut de NSView déroule le menu rendu par menuForEvent: — donc celui qu'AttachTo a posé. Cette méthode ne sert qu'à déclencher la même chose par programme.Placement : NSView se sert de selectionAnchorRect. Une vue qui ne l'implémente pas — c'est le cas des vues créées ici — voit le menu apparaître au CENTRE de ses limites ; les vues de texte d'AppKit le posent sur la sélection.
Shared Function ContextMenuKeySupported() As Boolean
Ne sert qu'à masquer un bouton là où il ne ferait rien : la touche, elle, n'a besoin d'aucun test.
Sub AddWritingToolsItems()
macOS 15.2. « Each call returns an array of newly allocated instances » : des items neufs, qu'on peut poser sans crainte de les partager — contrairement à l'image de coche des palettes.
Sub AutomaticallyInsertsWritingToolsItems(yes As Boolean)
macOS 15.2. Ne vaut QUE si le menu sert de menu contextuel — « if used as a context menu ». Un menu déroulé par PopUp n'en est pas un.

Propriétés

Count As Integer lecture seule
PresentationStyle As Styles
macOS 14. En Palette, le menu se présente en rangée compacte — mais il ne peut alors PAS être déroulé par PopUp ni attaché à un menu surgissant : il doit être le sous-menu d'un item d'un menu ordinaire.
SelectionMode As SelectionModes
macOS 14. N'agit que sur les items d'un même GROUPE de sélection — c'est-à-dire séparés par aucun séparateur ni en-tête.
ImageVisibility As ImageVisibilities
macOS 27. L'en-tête de NSMenuItem : à partir de macOS 27, AppKit décide de la visibilité des images d'items et « will typically hide images ». Visible par défaut dans cette classe, et non Automatic comme chez AppKit : un symbole passé à AddItem est une demande explicite. Vaut pour les items existants et à venir ; Automatic rend la décision au système.L'en-tête prévient que même Visible peut être outrepassé « in some cases ». Les pastilles d'un menu palette ne sont pas concernées : relevé sous macOS 27.0, leurs items n'ont pas d'image.

Événements

  • Event Chosen(index As Integer, title As String)

Énumérations

BadgesPlain=0Updates=1NewItems=2Alerts=3
ImageVisibilitiesAutomatic=0Visible=1Hidden=2
SelectionModesAutomatic=0SelectOne=1SelectAny=2
StylesRegular=0Palette=1
Surfaces

NativeVisualEffectView

classe

NSVisualEffectView, le fond translucide du système — celui de la barre latérale et de l'inspecteur, employé en interne depuis le début sans être exposé. Les matériaux sont sémantiques : on demande « barre latérale » ou « fond de fenêtre », jamais une couleur, et le système décide selon l'apparence, la transparence réduite et la place dans la fenêtre. Attention à Emphasized : l'en-tête prévient que peu de matériaux changent d'aspect — c'est sur Selection que cela se voit.

Constructeur

Sub Constructor(width As Double = 260, height As Double = 200, material As Materials = Materials.WindowBackground, blending As Blendings = Blendings.BehindWindow)

Les matériaux sont SÉMANTIQUES : on demande « barre latérale » ou « fond de fenêtre », pas une couleur. Le système décide du rendu selon l'apparence, le réglage de transparence réduite et la position dans la fenêtre. Les anciens Light et Dark sont dépréciés depuis 10.14 et ne sont pas exposés ici.

Méthodes

Sub AddView(view As Ptr, x As Double, y As Double, width As Double, height As Double)
Coordonnées AppKit, origine EN BAS : une NSVisualEffectView n'est pas inversée. Pour compter depuis le haut, poser d'abord une vue de NativeControlHost.MakeFlippedContainer et y ajouter le contenu.
Function Handle() As Ptr
Sub SetContentView(view As Ptr)
Une seule vue, occupant toute la surface et suivant les redimensionnements.
Sub SetCornerRadius(radius As Double)
Passe par le calque, et c'est ici sans danger : un RAYON n'est pas une couleur. Les CGColor posés dans un calque sont figés au moment de l'écriture et ne suivent pas le mode sombre — une géométrie, si.

Propriétés

Blending As Blendings
BehindWindow laisse voir le bureau et les fenêtres derrière ; WithinWindow ne mélange qu'avec ce qui est derrière la vue DANS la fenêtre. Le premier n'a d'effet que si la fenêtre elle-même est translucide.
Emphasized As Boolean
10.12+. Sert à signaler qu'une vue associée a le focus clavier. ATTENTION, l'en-tête est explicite : « Some, but not all, materials change their look when emphasized. » Sur la plupart des matériaux — Sidebar, WindowBackground, Popover… — l'effet est nul ou imperceptible. C'est sur SELECTION qu'il se voit : le matériau passe de la teinte d'accentuation au gris, exactement comme une ligne sélectionnée dans une liste qui perd le focus.
Material As Materials
State As States
FollowsWindowActiveState est le comportement du système : le matériau s'éteint quand la fenêtre passe à l'arrière-plan.

Énumérations

BlendingsBehindWindow=0WithinWindow=1
MaterialsTitlebar=3Selection=4Menu=5Popover=6Sidebar=7HeaderView=10Sheet=11WindowBackground=12HUDWindow=13FullScreenUI=15ToolTip=17ContentBackground=18UnderWindowBackground=21UnderPageBackground=22
StatesFollowsWindowActiveState=0Active=1Inactive=2
Surfaces

NativeSceneView

classe

Un modèle 3D vivant — qu'on tourne à la souris, éclairé, animé — rendu entièrement dans le processus : SCNView est une NSView ordinaire. C'est la seule façon d'afficher de la 3D sans QLPreviewView, dont la vue hors processus détruit le glisser-déposer. Show tente sceneWithURL: puis passe par ModelIO, ce qui ajoute le STL ; CanShow dit à l'avance si le format est du ressort de SceneKit.

Constructeur

Sub Constructor(width As Double = 420, height As Double = 170)

POURQUOI PAS QLPreviewView, qui ferait la même chose en une ligne : il installe une NSRemoteView servie par SceneKitQLPreviewExtension, et afficher un modèle 3D détruit alors DÉFINITIVEMENT le glisser-déposer du processus — mesuré, rien ne le rétablit hormis quitter l'application. SCNView est une NSView ordinaire : rien ne sort du processus, sinon l'analyse du fichier.

POURQUOI PAS RealityKit, qui remplace SceneKit depuis macOS 26 : il n'expose AUCUNE classe de vue à l'Objective-C — ni ARView, ni RealityView, ni Entity. Vérifié à l'exécution : les seules classes ObjC du framework sont de l'interne Swift aux noms décorés. RealityKit ne se pilote qu'en Swift, donc pas depuis Xojo. SceneKit est déprécié mais reste, à ce jour, la seule voie praticable.

Méthodes

Function Available() As Boolean
Sub Clear()
Function Handle() As Ptr
Function Item() As FolderItem
Shared Function CanShow(item As FolderItem) As Boolean
« Handles » aurait été le nom naturel — c'est un MOT RÉSERVÉ de Xojo, celui des gestionnaires de menu. Et la casse n'y change rien.Les formats que SceneKit ouvre par lui-même ou via ModelIO. Une LISTE, et c'est assumé : SceneKit n'offre aucun moyen de demander « sais-tu lire ceci ? » sans tenter la lecture, ce qui coûterait le chargement complet.
Function Show(item As FolderItem) As Boolean
DEUX chemins, et le second rattrape le premier : sceneWithURL: connaît les formats natifs de SceneKit, ModelIO en ouvre d'autres — dont le STL. On essaie le direct, puis la passerelle.

Propriétés

CameraControl As Boolean
Laisse l'utilisateur tourner, approcher, déplacer le modèle à la souris.
RendersContinuously As Boolean
Redessine en continu, à la fréquence de l'écran : nécessaire pour une ANIMATION contenue dans le fichier. Coûteux, donc au choix.
Surfaces

NativeBox

classe

NSBox : cadre de groupe, conteneur personnalisé et — sous-employé — séparateur, horizontal ou vertical selon ses proportions. Sa vertu tient en un point : il peint avec de vraies NSColor, donc il suit le mode sombre tout seul, là où un CGColor posé dans un CALayer est figé à l'écriture.

Constructeur

Sub Constructor(width As Double = 300, height As Double = 200, kind As Kinds = Kinds.Custom)

Sa vertu tient en un point : un NSBox peint avec de VRAIES NSColor. Il suit donc le mode sombre et le contraste renforcé tout seul, là où un CGColor posé dans un CALayer est figé à l'instant où on l'écrit et n'est jamais remis à jour. C'est la raison pour laquelle NativeRichTextEditor est bâti en NSBox.

Méthodes

Sub AddView(view As Ptr, x As Double, y As Double, width As Double, height As Double)
Ajoute au contenu. Si UseFlippedContent a été appelé, y compte depuis le HAUT ; sinon c'est le repère AppKit, origine en bas.
Function ContentView() As Ptr
La vue où loger le contenu : celle qu'on a posée, ou celle que NSBox gère.
Function Handle() As Ptr
Shared Function Separator(x As Double, y As Double, width As Double, height As Double) As NativeBox
Un séparateur : horizontal ou vertical selon ses proportions, et il prend la teinte du système sans qu'on la nomme. Une vue d'un point d'épaisseur peinte à la main n'aurait ni la bonne couleur ni le bon comportement en mode sombre.
Sub SetColors(fill As Color, border As Color, borderWidth As Double = 1, cornerRadius As Double = 0)
N'a d'effet qu'en type Custom : les autres types se dessinent eux-mêmes.
Sub SetContentView(view As Ptr)
Sub SetSystemColors(fillName As String = "controlBackgroundColor", borderName As String = "separatorColor", borderWidth As Double = 1, cornerRadius As Double = 6)
La bonne façon : des couleurs SÉMANTIQUES, vivantes, qui suivent l'apparence. Un nom inconnu du système est ignoré plutôt que de peindre du noir.
Sub SetTitle(title As String, position As TitlePositions = TitlePositions.AtTop)
Sub SetTransparent(transparent As Boolean)
Ni fond ni bordure, mais le titre et la disposition restent : le moyen de grouper sans rien dessiner.
Sub UseFlippedContent(width As Double, height As Double)
Remplace la vue de contenu par une vue INVERSÉE : y compte alors depuis le haut, comme dans le concepteur Xojo et comme partout ailleurs ici.

Énumérations

KindsPrimary=0Separator=2Custom=4
TitlePositionsNone=0AboveTop=1AtTop=2BelowTop=3AboveBottom=4AtBottom=5BelowBottom=6

Layout

Les deux seuls contrôles qui suppriment les coordonnées en dur : on décrit, AppKit calcule.

Layout

NativeGridView

classe

NSGridView (10.12+) : une grille en Auto Layout. On décrit des rangées, AppKit calcule positions et largeurs de colonnes. Une rangée ou une colonne masquée se réduit à zéro et cache ses vues — le moyen propre de faire disparaître une option sans démonter la grille.

Constructeur

Sub Constructor(columnSpacing As Double = 12, rowSpacing As Double = 8)

Deux faits vérifiés en Objective-C avant d'écrire ceci : 1) construite par initWithFrame:, la grille garde translatesAutoresizingMaskIntoConstraints à YES — elle se place donc par cadre comme tout le reste de la bibliothèque ; 2) addRowWithViews: met ce même drapeau à NO sur les vues qu'on lui donne. L'appelant n'a rien à faire : la grille prend la main sur ses enfants.

Méthodes

Function AddRow(ParamArray views() As Ptr) As Integer
Rend l'indice de la rangée créée. Pour une case vide, passer EmptyCell — AppKit s'en sert comme marqueur, un Nil dans le tableau ne conviendrait pas.
Function CellView(row As Integer, column As Integer) As Ptr
Shared Function EmptyCell() As Ptr
Marqueur de case vide, à passer à AddRow. C'est une propriété de CLASSE de NSGridCell, pas une instance à créer.
Function FittingSize() As Cocoa.NSSize
La taille naturelle calculée par Auto Layout. ATTENTION : elle est exprimée en rectangles d'ALIGNEMENT — le cadre d'un NSButton déborde du sien de quelques points. Une grille de boutons mérite donc un peu de marge.
Function Handle() As Ptr
Sub MergeCells(column As Integer, columnCount As Integer, row As Integer, rowCount As Integer)
Fusionne un bloc rectangulaire — un titre qui court sur toute la largeur, par exemple. La case gardée est celle en haut à gauche du bloc.
Sub Refit(padding As Double = 0)
Ajuste le cadre à la taille naturelle. Le supplément compense le débord des rectangles d'alignement quand la grille contient des boutons.
Sub SetColumnHidden(column As Integer, hidden As Boolean)
Une colonne masquée se réduit à zéro ET masque ses vues : c'est le moyen propre de faire disparaître une option sans démonter la grille.
Sub SetColumnWidth(column As Integer, width As Double)
Passer SizeForContent rend la colonne à l'ajustement automatique.
Sub SetPlacement(horizontal As Placements, vertical As Placements)
Placement par DÉFAUT de la grille. Rangées, colonnes et cases peuvent le redéfinir ; « Inherited » sur une case renvoie au niveau supérieur.
Sub SetRowAlignment(alignment As RowAlignments)
FirstBaseline aligne les lignes de base d'une rangée : c'est ce qui fait qu'un libellé et un champ paraissent posés sur la même ligne, là où un centrage vertical les décale visiblement.
Sub SetRowHeight(row As Integer, height As Double)
Sub SetRowHidden(row As Integer, hidden As Boolean)
Sub SetRowPadding(row As Integer, top As Double, bottom As Double)
L'espace total entre deux rangées vaut bottomPadding de la première, plus rowSpacing, plus topPadding de la seconde.
Sub SetSpacing(columnSpacing As Double, rowSpacing As Double)
Shared Function SizeForContent() As Double
NSGridViewSizeForContent, la sentinelle « ajuste-toi au contenu ». C'est un CGFloat exporté valant FLT_MIN : on le LIT plutôt que de recopier un littéral, la comparaison d'AppKit étant une égalité exacte.

Propriétés

ColumnCount As Integer lecture seule
RowCount As Integer lecture seule

Énumérations

PlacementsInherited=0None=1Leading=2Trailing=3Center=4Fill=5
RowAlignmentsInherited=0None=1FirstBaseline=2LastBaseline=3
Layout

NativeStackView

classe

NSStackView : une rangée ou une colonne qui se répartit toute seule, avec six modes de distribution et des priorités de visibilité — c'est le mécanisme des barres qui se dégarnissent quand la place manque.

Constructeur

Sub Constructor(orientation As Orientations = Orientations.Horizontal, spacing As Double = 8)

PIÈGE DE CONSTRUCTION, vérifié en Objective-C : la fabrique de classe stackViewWithViews: rend une pile dont translatesAutoresizingMaskIntoConstraints vaut NO — impossible à placer par cadre, elle ignorerait le sien. initWithFrame: le laisse à YES, et c'est donc la seule voie compatible avec le reste de la bibliothèque.

Méthodes

Sub AddView(view As Ptr)
addArrangedSubview: — la pile prend la main sur le placement de la vue et met son translatesAutoresizingMaskIntoConstraints à NO, comme le fait NSGridView. Rien à régler côté appelant.
Sub AddViews(ParamArray views() As Ptr)
Function FittingSize() As Cocoa.NSSize
Taille naturelle, exprimée en rectangles d'ALIGNEMENT : le cadre d'un NSButton déborde du sien de quelques points. Une pile de boutons a donc besoin d'un supplément — voir Refit.
Function Handle() As Ptr
Sub InsertView(view As Ptr, index As Integer)
Sub Refit(padding As Double = 0)
Sub RemoveView(view As Ptr)
Retire la vue de la disposition ET de la hiérarchie : removeArrangedSubview: seul la laisserait sous-vue, donc dessinée mais plus placée.
Sub SetCustomSpacing(afterView As Ptr, spacing As Double)
Espacement particulier APRÈS une vue donnée — c'est ainsi qu'on sépare des groupes dans une même pile sans y glisser de vue vide.
Sub SetDetachesHiddenViews(detaches As Boolean)
Quand une vue masquée est détachée, la pile se resserre comme si elle n'existait pas. Sinon elle garde sa place, vide.
Sub SetInsets(top As Double, leading As Double, bottom As Double, trailing As Double)
Sub SetVisibilityPriority(view As Ptr, priority As Double)
Sous 1000, la pile a le droit de détacher la vue quand la place manque — c'est le mécanisme des barres qui se dégarnissent en rétrécissant. MustHold = 1000, DetachOnlyIfNecessary = 900, NotVisible = 0.

Propriétés

Alignment As Alignments
Alignement sur l'axe TRANSVERSE : pour une pile horizontale, CenterY, Top, Bottom ou FirstBaseline ; pour une verticale, CenterX, Leading ou Trailing. Un alignement pris sur le mauvais axe est simplement ignoré.
Distribution As Distributions
Orientation As Orientations
Spacing As Double

Énumérations

AlignmentsTop=3Bottom=4Leading=5Trailing=6CenterX=9CenterY=10FirstBaseline=12
DistributionsGravityAreas=-1Fill=0FillEqually=1FillProportionally=2EqualSpacing=3EqualCentering=4
OrientationsHorizontal=0Vertical=1

System

Ce qui ne vise aucune fenêtre : la barre de menus du système, et les panneaux de fichiers.

System

NativeStatusItem

classe

NSStatusItem : un extra dans la barre de menus. Xojo ne sait pas en poser du tout. Depuis 10.10 tout passe par button — titre, image, cible et action de l'item lui-même sont dépréciés.

Constructeur

Sub Constructor(title As String = "", symbolName As String = "")

Longueur variable : l'item s'ajuste à son contenu. NSSquareStatusItemLength (-2) le garderait carré, à la hauteur de la barre.

Méthodes

Sub AddMenuItem(title As String)
Un item de menu porte sa propre cible et son propre tag, comme dans NativeComboButton : c'est le tag qui dit lequel a été choisi.
Sub AddSeparator()
Function Handle() As Ptr
Sub Remove()
Sans cet appel, l'extra reste dans la barre de menus jusqu'à la fin du processus, même si l'objet Xojo a disparu.
Sub SetSymbol(symbolName As String, accessibilityDescription As String = "")

Propriétés

Title As String
Visible As Boolean

Événements

  • Event Clicked(index As Integer, title As String)
System

NativeFilePanel

classe

NSSavePanel et NSOpenPanel réunis, puisque le second hérite du premier. Ce que les dialogues Xojo n'ont pas : une vue accessoire — les options de format sous le champ de nom, comme dans l'export d'Aperçu.

Constructeur

Sub Constructor(mode As Modes = Modes.Save)

Les deux panneaux partagent une classe ici parce qu'ils partagent presque tout : NSOpenPanel hérite de NSSavePanel.

Méthodes

Function Handle() As Ptr
Function RunModal() As Boolean
Rend True si l'utilisateur a validé. NSModalResponseOK vaut 1 — à ne pas confondre avec le 1000 de NSAlert, qui compte à partir de NSAlertFirstButtonReturn.
Sub SetAccessoryView(view As Ptr, width As Double = 0, height As Double = 0)
N'importe quelle NSView — donc le Handle de n'importe quel contrôle de la bibliothèque. Le panneau se dimensionne sur le cadre fourni.
Sub SetAllowedExtensions(ParamArray extensions() As String)
allowedContentTypes veut des UTType (macOS 11+), pas des chaînes. On les construit par extension ; une extension inconnue du système rend Nil et est simplement ignorée.
Sub SetOpenOptions(chooseFiles As Boolean = True, chooseDirectories As Boolean = False, multipleSelection As Boolean = False)
Sans effet sur un panneau d'enregistrement : ces réglages n'existent que sur NSOpenPanel.
Sub SetTexts(title As String = "", message As String = "", prompt As String = "")
prompt est le libellé du bouton de validation. Passer "" laisse le texte par défaut du système, déjà localisé — mieux vaut ne pas le traduire soi-même.
Function Values() As FolderItem()
Le pluriel n'a de sens qu'en ouverture avec sélection multiple ; ailleurs le tableau contient au plus un élément.
Sub ShowContentTypes(visible As Boolean)
macOS 15. Le menu de FORMAT sous le champ de nom, dessiné et peuplé par AppKit d'après les types autorisés — ce qu'il fallait fabriquer soi-même dans une vue accessoire. Sans effet à l'ouverture, ni si aucun type n'a été déclaré.
Function ChosenContentType() As String
Le type retenu, en identifiant uniforme. À lire APRÈS validation.

Propriétés

Directory As FolderItem
FileName As String
Le nom proposé dans le champ. Sans objet sur un panneau d'ouverture.
Value As FolderItem lecture seule
Valide seulement après un RunModal accepté.

Énumérations

ModesSave=0Open=1
System

NativeFileKind

classe

Reconnaît ce que le Finder montre et que Xojo ignore : une application, un paquet d'installation, une bibliothèque Photos sont des dossiers pour le système de fichiers — FolderItem.IsFolder rend True — mais des documents pour l'utilisateur. Classify rend le genre, TypeIdentifier l'identifiant de type (com.apple.photos.library), et Describe le libellé du Finder, traduit par le système.

Méthodes

Shared Function Classify(item As FolderItem) As Kinds
Ce que le Finder voit, et que Xojo ne dit pas : une application, un paquet d'installation, une bibliothèque Photos sont des DOSSIERS pour le système de fichiers — FolderItem.IsFolder rend True — mais des documents pour l'utilisateur. La distinction s'appelle un « paquet », et seul macOS la connaît.L'ordre des questions compte : un alias vers une application est d'abord un alias, et une application est un paquet avant d'être un dossier.
Shared Function Describe(item As FolderItem) As String
Le « genre » du Finder, traduit par le système : « Application », « Paquet d'installation », « Bibliothèque Photos », « Dossier ». On ne le fabrique pas soi-même — la traduction est celle de macOS.
Shared Function IsApplication(item As FolderItem) As Boolean
Shared Function IsPackage(item As FolderItem) As Boolean
Vrai pour tout ce que le Finder présente comme un document alors que c'est un dossier : application, paquet d'installation, bibliothèque Photos, projet Xcode, document RTFD…
Shared Function TypeIdentifier(item As FolderItem) As String
L'identifiant de type uniforme : « com.apple.application-bundle », « com.apple.photos.library », « public.folder ». C'est lui qui permet de reconnaître la bibliothèque d'une application donnée.

Énumérations

KindsMissing=0PlainFile=1Folder=2AliasFile=3Application=4InstallerPackage=5Package=6
System

NativeQuickLook

classe

QLPreviewView : l'aperçu du Finder dans une vue à soi — PDF, image, son, vidéo, texte. Xojo n'a rien pour cela. Preview(unFichier) suffit ; Available() dit si le framework a pu être chargé, et Handle rend Nil sinon. Il se pose sans risque sous une zone de dépôt : un QLPreviewView n'enregistre aucun type de glissement — vérifié — et ne peut donc pas disputer le dépôt à la vue posée par-dessus. Le puits devient alors lui-même l'aperçu de ce qu'on y laisse tomber.

Constructeur

Sub Constructor(width As Double = 320, height As Double = 320, style As Styles = Styles.Normal)

UNE PARTICULARITÉ, et elle est décisive : QLPreviewView n'appartient pas à AppKit mais à QuickLookUI, que Xojo ne lie jamais. Sans chargement explicite, la classe n'existe tout simplement pas — vérifié : un binaire qui ne lie pas Quartz ne trouve pas QLPreviewView. D'où le dlopen, sur le CHEMIN COMPLET : le nom court « Quartz » échoue.

Méthodes

Sub Close()
LIBÈRE l'aperçu et ses ressources — c'est le seul geste qui le fasse.L'en-tête est formel : sans close, « votre application fuit ». Et comme shouldCloseWithWindow vaut True par défaut, close n'arrive de lui-même qu'à la fermeture de la FENÊTRE : dans une application à fenêtre unique, cela veut dire « à la sortie ». Un aperçu vivant retient donc son service QuickLook pendant toute la session. ATTENTION, et c'est irréversible : une fois fermée, la vue N'ACCEPTE PLUS aucun élément. Pour prévisualiser de nouveau, il faut en construire une autre — d'où Available() qui rendra False après coup.
Function Available() As Boolean
On interroge la vue obtenue, pas le numéro de version : QuickLookUI existe depuis 10.7, mais son chargement peut échouer pour d'autres raisons. Une vue FERMÉE n'est plus utilisable non plus, et le dit ici.
Sub Clear()
Function Handle() As Ptr
Function Item() As FolderItem
Function Preview(item As FolderItem) As Boolean
VÉRIFIÉ : NSURL se conforme DÉJÀ au protocole QLPreviewItem — son previewItemURL rend l'URL elle-même. Il n'y a donc aucune classe d'exécution à fabriquer, contrairement à ce que la lecture de l'en-tête laisse craindre.
Sub Refresh()
À appeler quand le FICHIER a changé sous l'aperçu : reposer le même item ne suffirait pas, QuickLook n'ayant aucune raison de le relire.

Propriétés

Autostarts As Boolean
Démarre seul les documents qui se jouent — un son, une vidéo.
CloseWithWindow As Boolean
À True, l'aperçu se referme avec la fenêtre qui le porte, ce qui dispense d'y penser. À False, c'est au Destructor de s'en charger.

Énumérations

StylesNormal=0Compact=1
System

NativeWindowMenu

classe

Le menu Fenêtre du système, et les commandes de fenêtre qui vont avec. Une fois le menu désigné par Install, AppKit le tient LUI-MÊME à jour : il y inscrit chaque fenêtre qui s'ouvre, l'en retire à la fermeture, coche celle du premier plan et bascule au clic. Xojo n'expose rien de tout cela.

Méthodes

Shared Sub Install(menu As DesktopMenuItem)
Désigne le sous-menu de cet item comme NSApplication.windowsMenu. On passe l'ITEM de barre de menus, pas le menu : côté ObjC, le sous-menu d'un NSMenuItem est le NSMenu attendu. Le Handle sans paramètre est vérifié par Cocoa.Responds(item, "submenu") avant usage — la forme paramétrée que documente la référence appartient à MenuItem, l'ancien nom, et aucune surcharge ne l'accepte.
Shared Function Installed() As Boolean
Constater plutôt que supposer : si le menu n'a pas pu être désigné, la liste ne se remplira jamais et rien d'autre ne le dirait.
Shared Sub Exclude(w As DesktopWindow, hidden As Boolean)
Une fenêtre de service — palette, inspecteur détaché — n'a rien à faire dans la liste. C'est une propriété de la FENÊTRE, pas du menu.
Shared Sub BringToFront(w As DesktopWindow)
makeKeyAndOrderFront: et non Show : sur une fenêtre déjà visible, Show ne la ramène pas devant et ne lui donne pas le focus clavier.
Shared Sub BringAllToFront()
L'action « Tout ramener au premier plan » du menu Fenêtre.
Shared Function Front() As DesktopWindow
La fenêtre CLÉ selon AppKit, qui n'est pas App.Window(0) : la liste de Xojo suit l'ordre de création, pas l'empilement.
Shared Sub PerformClose()
performClose: et non une fermeture forcée : le sélecteur système consulte le délégué de la fenêtre — windowShouldClose: peut refuser —, anime la fermeture et fait le bip quand la fenêtre n'a pas de case de fermeture.
Shared Sub ToggleFullScreen()
Le plein écran natif, celui du bouton vert, et non le FullScreen de Xojo qui se contente d'agrandir la fenêtre. Sans effet si la fenêtre ne porte pas son bouton de plein écran.
System

NativeDockTile

classe

L'icône de l'application dans le Dock : la pastille de compteur, et la possibilité d'y dessiner une vue à soi — jauge de progression, miniature du document, état. Xojo n'a rien pour cela.

Méthodes

Shared Sub SetBadge(text As String)
La pastille rouge — le « 3 » de Mail. Une chaîne vide la retire. AppKit tronque de lui-même une étiquette trop longue : inutile de compter les caractères.
Shared Function Badge() As String
Ce que porte la pastille, chaîne vide si elle est absente.
Shared Sub SetContentView(view As Ptr)
L'icône devient une VUE, et l'on y dessine ce qu'on veut. Nil rétablit l'icône de l'application.
Shared Sub Display()
À appeler après CHAQUE modification de la vue de contenu : le Dock ne redessine pas de lui-même.
Shared Function Size() As Cocoa.NSSize
La taille utile de la vue, en points. Elle SUIT le réglage de taille du Dock : la coder en dur donnerait une jauge fausse dès que l'utilisateur le change.
Shared Sub ShowsApplicationBadge(visible As Boolean)
Distinct de la pastille de texte : ce réglage décide si l'icône de l'application est incrustée dans la vue personnalisée. Sans vue personnalisée, il n'a rien à faire.
System

NativeHaptics

classe

Le petit à-coup du trackpad Force Touch, celui que l'on sent quand un glissement s'aligne sur un guide. La classe ne teste ni le matériel ni les réglages : l'en-tête dit que defaultPerformer rend le performer approprié « for the current input device, accessibility settings and user preferences ». Sans trackpad haptique, ou si l'utilisateur a coupé le retour, l'appel ne fait rien — c'est au système de décider.

Méthodes

Shared Sub Perform(pattern As Patterns = Patterns.Alignment, when As Timing = Timing.Default)
Attention au moment : Timing.Default vaut DrawCompleted, donc l'à-coup attend la passe de dessin suivante. Pour le sentir au clic, passer Timing.Now.
Shared Function Available() As Boolean
À n'employer que pour ADAPTER l'interface, jamais pour garder l'appel : Perform est déjà sans effet dans ce cas.

Énumérations

PatternsGeneric=0Alignment=1LevelChange=2
TimingDefault=0Now=1DrawCompleted=2
System

NativeCursor

classe

Les curseurs apparus avec macOS 15 : redimensionnement de colonne et de rangée, poignée de cadre, loupes. Les directions passées ne sont pas décoratives — elles disent dans quels sens le tirage est encore possible, si bien qu'une colonne déjà à sa largeur minimale montre un curseur qui ne pointe plus que d'un côté.

Méthodes

Shared Sub SetColumnResize(directions As Horizontal = Horizontal.All) · SetRowResize
Les curseurs du Finder en mode colonnes et d'un tableau.
Shared Sub SetFrameResize(position As FramePositions, directions As FrameDirections = FrameDirections.All)
Le curseur d'une POIGNÉE de cadre : on lui donne le coin ou le bord saisi, et les sens encore possibles.
Shared Sub SetZoom(zoomIn As Boolean)
La loupe « plus » et la loupe « moins ».
Shared Sub Restore()
Dépile UN curseur. Les poses passent par push et non set : un curseur posé par set est écrasé au prochain survol d'un contrôle. La pile d'AppKit n'a pas de « tout remettre », donc autant de Restore que de poses.
Shared Function Available() As Boolean
Pour ADAPTER l'interface seulement : les méthodes ci-dessus sont déjà sans effet sous un système antérieur.

Énumérations

HorizontalLeft=1Right=2All=3
VerticalUp=1Down=2All=3
FramePositionsTop=1Left=2TopLeft=3Bottom=4BottomLeft=6Right=8TopRight=9BottomRight=12
FrameDirectionsInward=1Outward=2All=3
System

NativePasteboard

classe

Le presse-papiers général vu sous l'angle de l'alerte d'accès de macOS 15.4 — celle qui prévient l'utilisateur qu'une application vient de lire son presse-papiers.

Méthodes

Shared Function AccessBehavior() As Behaviors
macOS 15.4. Ce que le système fait quand l'application lit le presse-papiers PAR PROGRAMME : demander, autoriser d'office, refuser d'office. L'utilisateur le règle par application dans les Réglages Système. Deux nuances que l'en-tête énonce : tant qu'une application n'a JAMAIS déclenché l'alerte, elle rapporte Default — c'est le premier accès qui fait basculer l'état vers Ask, si bien que lire Default ne signifie pas « aucune alerte ne viendra » ; et ce réglage ne touche PAS ce qui découle d'un geste de l'utilisateur — un glisser-déposer, un Cmd-V ne demandent jamais rien.
Shared Function ChangeCount() As Integer
Le compteur de modifications, incrémenté à chaque écriture par qui que ce soit. C'est le pendant utile du précédent : le lire ne compte pas comme un accès au contenu, donc il ne déclenche aucune alerte. Une application qui veut activer un bouton « Coller » interroge ce compteur au lieu de lire le presse-papiers.
Sub Constructor() · Function Detect(ParamArray patterns() As Patterns) As Boolean
macOS 15.4. Demande si le PREMIER élément du presse-papiers correspond à l'un des motifs. Tout l'intérêt tient à une phrase de l'en-tête — « without notifying the person using the app » : on apprend ce qu'il y a sans lire, donc sans déclencher l'alerte. Le rappel ne rend que les motifs RECONNUS, jamais les valeurs : les obtenir demanderait de lire, et cela, le système le signale. Rend False si l'appel n'a pas pu partir — l'événement n'arrivera alors jamais, et c'est aussi le cas quand une détection est déjà en vol : une seule à la fois.
Shared Function DetectionAvailable() As Boolean
Pour ADAPTER l'interface : Detect rend déjà False sinon.
Shared Function Available() As Boolean
Pour ADAPTER l'interface seulement : AccessBehavior rend déjà Default sous un système antérieur.

Événements

  • Event Detected(patterns() As Patterns, failed As Boolean)

Le bloc de complétion arrive sur une file de service, PAS sur le fil de l'interface. Il se contente donc de retenir le NSSet et de poser un drapeau, puis appelle Cocoa.PerformOnMainThread : Detected est levé depuis le fil principal, où les chaînes peuvent se fabriquer sans danger. C'est ce retain qui impose l'unicité — deux détections en vol se disputeraient le même pointeur depuis deux fils.

Énumérations

PatternsProbableWebURLProbableWebSearchNumberLinkPhoneNumberEmailAddressPostalAddressCalendarEventShipmentTrackingNumberFlightNumberMoneyAmount
BehaviorsDefault=0Ask=1AlwaysAllow=2AlwaysDeny=3
System

NativeSymbolEffect

classe

Anime un symbole SF : rebond, pulsation, tracé… Utilitaire partagé, pas un contrôle — les méthodes sont Shared et s'appliquent à n'importe quelle NSImageView. Deux limites vérifiées dans les en-têtes : les effets vivent dans Symbols.framework et non AppKit, d'où un chargement explicite ; et côté AppKit addSymbolEffect: n'existe QUE sur NSImageView, contrairement à UIKit où les boutons l'acceptent.

Méthodes

Shared Sub Play(imageView As Ptr, kind As Effects)
L'image doit être un vrai symbole SF : sur une image ordinaire, l'effet n'a rien à animer.
Shared Sub RemoveAll(imageView As Ptr)
Les effets indéfinis — pulsation, couleur variable, rotation — tournent jusqu'ici ; les ponctuels s'arrêtent d'eux-mêmes.
Shared Function Available(kind As Effects) As Boolean
Chaque effet est une classe distincte, apparue à une version différente. On interroge la classe, jamais le numéro de système.

Énumérations

EffectsPulse=0Bounce=1VariableColor=2Scale=3Appear=4Disappear=5Wiggle=6Rotate=7Breathe=8DrawOn=9DrawOff=10

Disponibilité : les six premiers depuis macOS 14, Wiggle/Rotate/Breathe depuis macOS 15, DrawOn/DrawOff depuis macOS 26.

System

NativeLoginItem

classe

Inscrit l'application — ou un service qu'elle transporte — à l'ouverture de session, par SMAppService (macOS 13). Remplace SMLoginItemSetEnabled, retiré, et l'écriture directe dans les préférences d'ouverture, qui n'a jamais été une API. Le framework ServiceManagement n'étant pas lié par une application Xojo, la classe le charge elle-même.

Fabriques

Shared Function MainApp() As NativeLoginItem
L'application elle-même. Le cas courant, et le seul qui ne demande rien de plus qu'un paquet .app normal.
Shared Function LoginItem(bundleIdentifier As String) As NativeLoginItem
Une application auxiliaire livrée sous Contents/Library/LoginItems.
Shared Function Agent(plistName As String) As NativeLoginItem
Un LaunchAgent sous Contents/Library/LaunchAgents : dans la session, avec les droits de la personne connectée.
Shared Function Daemon(plistName As String) As NativeLoginItem
Un LaunchDaemon sous Contents/Library/LaunchDaemons : en root, hors session. Son inscription demande une authentification d'administrateur.

Méthodes

Function Register(ByRef errorMessage As String) As Boolean
True veut dire que la demande a abouti, pas forcément que le service est actif : le statut qui suit peut valoir RequiresApproval.
Function Unregister(ByRef errorMessage As String) As Boolean
Sans effet et sans erreur si le service n'était pas inscrit.
Function Status() As Statuses
L'état tel que le système le voit. À relire après chaque geste : la personne a pu tout changer dans Réglages Système entre-temps.
Shared Sub OpenSystemSettings()
Ouvre Réglages Système › Général › Ouverture et extensions. Le seul geste possible quand le statut vaut RequiresApproval.
Shared Function Available() As Boolean
macOS 13. Avant, il n'y a rien à quoi se rabattre.
Function Handle() As Ptr

Énumérations

StatusesUnavailable=-1NotRegistered=0Enabled=1RequiresApproval=2NotFound=3

Le système refuse d'inscrire un exécutable qu'il ne peut pas identifier : une application non signée, ou lancée hors de son paquet .app, voit Register rendre False avec un message explicite. En débogage, ce que l'on inscrit est le paquet .debug.app, pas l'application livrée. statusForLegacyURL: n'est pas repris : il ne sert qu'à migrer depuis l'époque pré-13.

System

NativeWorkspace

classe

Le service par lequel une application parle au Finder. Pour l'instant une seule chose, celle qui manquait le plus souvent : « Révéler dans le Finder » — le Finder passe au premier plan et ouvre une fenêtre où les fichiers sont DÉJÀ SÉLECTIONNÉS. Aucun équivalent Xojo : FolderItem.Open LANCE le fichier, et ouvrir le dossier parent laisse l'utilisateur chercher des yeux.

Méthodes

Shared Function Reveal(files() As FolderItem) As Boolean
macOS 10.6, activateFileViewerSelectingURLs:. Plusieurs fichiers à la fois : le Finder les sélectionne tous et ouvre autant de fenêtres qu'il y a de dossiers concernés — ce qu'aucun contournement par le dossier parent ne reproduit.Le retour dit « la demande a été transmise au Finder », pas « le Finder a réussi » : le sélecteur ne rend rien, l'en-tête le déclare void. Ce que Reveal vérifie de son côté, c'est qu'au moins un fichier EXISTE — sans quoi l'appel part dans le vide et il ne se passe rien de visible.
Shared Function Reveal(file As FolderItem) As Boolean
Le cas d'un seul fichier, qui est le plus courant.
System

NativeUserNotification

classe

Notifications système par UNUserNotificationCenter (macOS 10.14), en remplacement de NSUserNotification, déprécié et silencieusement inopérant sur les systèmes récents. Tout y est asynchrone : chaque demande part, et la réponse arrive plus tard par un événement.

Méthodes

Function RequestAuthorization(alerts As Boolean = True, sounds As Boolean = True, badges As Boolean = False, provisional As Boolean = False) As Boolean
La boîte du système n'apparaît QU'UNE FOIS dans la vie de l'application ; ensuite l'appel rend la réponse enregistrée sans rien montrer. provisional demande une autorisation discrète : aucune boîte, et les notifications arrivent silencieusement dans le centre.
Sub RequestSettings()
Lit l'état de l'autorisation sans rien demander à personne. Réponse par SettingsRead.
Function Send(identifier As String, title As String, body As String, subtitle As String = "", delaySeconds As Double = 0, withSound As Boolean = True, categoryIdentifier As String = "") As Boolean
Un delaySeconds nul veut dire « tout de suite » : aucun déclencheur n'est attaché. Un même identifiant REMPLACE la notification précédente — c'est ainsi qu'on met à jour une progression sans empiler dix bannières.
Sub RequestPendingNotifications() · Sub RequestDeliveredNotifications()
Ce qui est programmé, et ce qui est encore visible dans le centre. Réponses par PendingRead et DeliveredRead.
Sub RemovePendingRequests(ParamArray identifiers() As String) · Sub RemoveAllPendingNotifications()
Sub RemoveDeliveredNotifications(ParamArray identifiers() As String) · Sub RemoveAllDeliveredNotifications()
Sub SetBadgeCount(value As Integer)
macOS 13. Pastille posée par le centre de notifications, donc soumise à l'autorisation « badges ». Pour une pastille qui n'en dépend pas, voir NativeDockTile.
Sub AddResponseCategory(category As NativeNotificationCategory)
Déclare au système un jeu de boutons — et éventuellement un champ de saisie. Avant l'envoi de la notification qui s'y rattache : déclarer après coup ne rattrape rien. Une catégorie de même identifiant est remplacée, pas dupliquée.
Sub RemoveAllResponseCategories()
setNotificationCategories: remplace l'ensemble à chaque appel au lieu d'y ajouter ; la liste est donc tenue ici, et c'est elle qu'on vide.
Shared Sub SetForegroundPresentation(banner As Boolean = True, inList As Boolean = True, sound As Boolean = True, badge As Boolean = False)
Ce que le système affiche quand une notification arrive alors que l'application est active. Tout à False revient à ne rien montrer — le comportement de macOS sans delegate, précisément celui que cette classe corrige. Réglage partagé : le centre est un singleton.
Shared Sub OpenNotificationSettings()
Ouvre Réglages Système › Notifications, au volet de l'application. Le geste à proposer quand le statut vaut Authorized mais que AlertStyle vaut None : aucune API ne change ce réglage à la place de qui l'a choisi.
Shared Function Available() As Boolean

Propriétés en lecture seule

AlertStyle As AlertStyles
Valides après SettingsRead. C'est ce réglage, et non le statut d'autorisation, qui décide si une bannière paraît. Une application peut être autorisée avec un style None : le système accepte les notifications, les range dans le centre, et n'affiche jamais rien.
ShowsAlerts As DeviceSettings · ShowsInNotificationCenter As DeviceSettings · PlaysSounds As DeviceSettings · ShowsBadges As DeviceSettings

Événements

Event UserResponded(identifier As String, kind As Actions, actionIdentifier As String, textResponse As String)
La notification a été ouverte ou écartée. actionIdentifier porte la valeur brute ; kind la classe, en lisant les constantes exportées plutôt qu'en recopiant leur valeur.
Event AuthorizationAnswered(granted As Boolean, errorMessage As String)
Event SettingsRead(status As AuthorizationStatuses)
Event NotificationSent(identifier As String, errorMessage As String)
Event PendingRead(identifiers() As String) · Event DeliveredRead(identifiers() As String)

Énumérations

ActionsOpened=0Dismissed=1Custom=2
AlertStylesUnknown=-1None=0Banner=1Alert=2
DeviceSettingsUnknown=-1NotSupported=0Disabled=1Enabled=2
AuthorizationStatusesUnavailable=-1NotDetermined=0Denied=1Authorized=2Provisional=3Ephemeral=4

Xojo n'offre rien de tel sur macOS : toute sa section « Notifications » — Notification, TimeIntervalNotification, CalendarNotification, RemoteNotification et les classes de réponse, pilotées par MobileNotifications — porte « Project Types: Mobile, Operating Systems: iOS », et aucun de ces noms n'existe dans le framework de bureau 2026 R2.1. Cette classe ne double donc rien. Elle en reprend en revanche la nomenclature, délibérément : Send, RequestPendingNotifications, OpenNotificationSettings, les événements NotificationSent et UserResponded, les réglages AlertStyle, ShowsAlerts, ShowsInNotificationCenter, PlaysSounds, ShowsBadges, les énumérations AlertStyles, DeviceSettings, AuthorizationStatuses, et jusqu'aux catégories de réponse — AddResponseCategory et les classes NativeNotification…. Trois écarts assumés : AuthorizationAnswered porte l'accord, le refus et l'erreur là où Xojo sépare AuthorizationSucceeded et Error ; RequestSettings n'a pas d'équivalent ; et les énumérations gagnent une sentinelle que Xojo n'a pas.

L'autre raison de ne rien voir, celle-là hors de portée du code : « autorisée » ne veut pas dire « visible ». Si le style d'alerte vaut None, le système accepte tout et n'affiche rien. RequestSettings le dit, OpenNotificationSettings mène au bon volet, et aucune API ne change ce réglage à la place de qui l'a choisi.

Le delegate est posé d'office, et l'en-tête dit pourquoi : « The method will be called on the delegate only if the application is in the foreground. If the method is not implemented […] the notification will not be presented. » Sans lui, une notification envoyée pendant que l'application est active part, est acceptée, se range dans le centre — et ne s'affiche jamais, sans qu'aucune erreur ne le signale. Le Constructor construit donc une classe ObjC au runtime, à la manière de NativeControlHost, et SetForegroundPresentation règle ce qui doit paraître.

Les blocs de complétion arrivent sur une file de service, PAS sur le fil de l'interface. Chaque bloc se contente donc de retenir le résultat brut, puis appelle Cocoa.PerformOnMainThread : les événements de cette classe partent tous du fil principal. Conséquence : l'instance doit vivre dans une propriété, jamais dans une variable locale — le système peut appeler ses blocs après sa destruction.

Les boutons de réponse passent par AddResponseCategory : une NativeNotificationCategory portant des NativeNotificationButton et, si l'on veut, un NativeNotificationTextField. UserResponded rapporte alors l'identifiant de l'action choisie et, pour un champ, le texte tapé. Une réserve subsiste pour le clic ayant LANCÉ l'application : le delegate doit être en place avant la fin du démarrage, donc l'instance créée dans App.Opening.

System

NativeNotificationAction

classe

Classe de base d'une action de notification, sur le modèle du NotificationResponseAction de Xojo côté iOS : on n'en crée pas d'instance, on prend NativeNotificationButton ou NativeNotificationTextField.

Propriétés

Identifier As String
Ce que UserResponded rapportera. C'est lui qui distingue les actions entre elles, pas la légende.
Caption As String
Le texte du bouton, tel qu'il paraît.
BringToForeground As Boolean
Passe l'application au premier plan. Sans cela l'action est traitée sans que la fenêtre ne bouge — tout l'intérêt d'une notification interactive.
Destructive As Boolean
Bouton en rouge. Cosmétique, mais c'est la convention.
AuthenticationRequired As Boolean
Exige Touch ID, la montre ou le mot de passe avant d'agir.
SystemImageName As String
Un symbole SF sur le bouton (UNNotificationActionIcon, macOS 12). Ignoré sur un système antérieur, et absent de la classe iOS de Xojo : ajout d'ici.

Méthodes

Shared Function Available() As Boolean
Charge UserNotifications.framework au passage : une catégorie peut se monter avant qu'aucune instance de NativeUserNotification n'existe.
Function Build() As Ptr
Fabrique l'UNNotificationAction. Appelée par NativeNotificationCategory, redéfinie par NativeNotificationTextField.

L'ORDRE COMPTE : macOS tronque la liste des actions s'il manque de place, les plus utiles se mettent en tête.

System

NativeNotificationButton

classe

Un simple bouton sur une notification. Hérite de NativeNotificationAction, dont il tient tout son comportement — sur le modèle du NotificationResponseButton de Xojo.

Constructeur

Sub Constructor(caption As String, identifier As String)
Deux boutons « Oui » et « Non » se font avec deux instances, chacune avec son identifiant — c'est lui que UserResponded rapporte.
System

NativeNotificationTextField

classe

Un champ de saisie sur la notification, avec son bouton d'envoi : UNTextInputNotificationAction. Même ordre d'arguments que le NotificationResponseTextField de Xojo.

Constructeur et propriétés

Sub Constructor(caption As String, hint As String, sendCaption As String, identifier As String)
ButtonCaption As String · Hint As String
Le libellé du bouton d'envoi, et le texte d'invite du champ vide.

Ce que la personne a tapé arrive dans le paramètre textResponse de l'événement UserResponded, et nulle part ailleurs : la réponse ne transite pas par le contenu de la notification.

System

NativeNotificationCategory

classe

Le groupe de boutons et de champs qu'une notification pourra porter : UNNotificationCategory, sur le modèle du NotificationResponseCategory de Xojo. Le lien avec une notification tient à une seule chaîne, l'identifiant.

Constructeur, propriétés, méthode

Sub Constructor(identifier As String)
Cet identifiant est celui que l'on passera à Send comme categoryIdentifier.
Actions() As NativeNotificationAction
Les boutons et champs, dans l'ordre d'affichage.
CustomDismiss As Boolean
Fait remonter UserResponded même quand la notification est simplement ÉCARTÉE. Sans cela, un rejet passe inaperçu.
HiddenPreviewsBody As String · HiddenPreviewShowsTitle As Boolean · HiddenPreviewShowsSubtitle As Boolean
Ce qui reste visible quand les aperçus sont masqués — écran verrouillé, réglage « Afficher les aperçus » sur « Jamais ».
Function Build() As Ptr

Une catégorie n'a d'effet qu'une fois déclarée par NativeUserNotification.AddResponseCategory, et avant l'envoi de la notification qui s'y rattache : déclarer après coup ne rattrape rien. Le système les garde pour le compte de l'application, pas de l'instance.

CE QU'ON NE VERRA PAS TOUT DE SUITE : avec le style « Bannières », les boutons n'apparaissent qu'en survolant la notification et en la dépliant ; avec « Alertes », d'emblée. Le réglage appartient à la personne, pas à l'application. AllowInCarPlay et AllowAnnouncement, exposées par la classe iOS de Xojo, sont marquées API_UNAVAILABLE(macos) et ne sont donc pas reprises.