Generated reference › API — ICoreBlocks/ICoreStudio/ExternalCommunications
kind: generated#api#icoreblocks-icorestudio-externalcommunications

API — ICoreBlocks/ICoreStudio/ExternalCommunications

The public contract of 10 header(s) under src/ICoreBlocks/ICoreStudio/ExternalCommunications — 10 class/struct definition(s), 85 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.

ICoreActiveProjectFolder.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ICoreActiveProjectFolder.h

False until a project has actually been opened -- the state the app starts in, before the startup behaviour has picked one, and the state it stays in when there was nothing to reopen. getActiveProjectFolderPath() is then just the documents folder, which is not a project and must not be written to; ICoreStudioSerialization checks this before any save.

ICoreActiveProjectFolder#

ICoreActiveProjectFolder.h:4 · class · 13 declaration(s)

class ICoreActiveProjectFolder {
public:
    static std::filesystem::path getActiveProjectFolderPath();

    // False until a project has actually been opened -- the state the app starts
    // in, before the startup behaviour has picked one, and the state it stays in
    // when there was nothing to reopen. getActiveProjectFolderPath() is then just
    // the documents folder, which is not a project and must not be written to;
    // ICoreStudioSerialization checks this before any save.
    static bool hasActiveProject();

    // Sets the active project's name (the folder/.iproj stem). Used by the Project
    // Navigator; getActiveProjectFolderPath() == documentsFolderPath / projectName.
    static void setProjectName(const std::string& name);

    // Empty when no project is open (the hasActiveProject() == false state).
    // Read by anything that has to put the active project back exactly as it
    // found it -- the regression sandbox does, and deriving the name from
    // getActiveProjectFolderPath().filename() would not survive a project name
    // that happens to match the documents folder's own.
    static const std::string& getProjectName();

    static void saveProjectSerializationToProjectFolder(const std::vector<std::string> &serializedProject);

    // Reads the project's .iproj. An empty result is AMBIGUOUS on its own and
    // the caller must not treat it as "an empty project": it is also what a file
    // that is present but unreadable (permissions, a lock, an IO error) returns.
    //
    // `readFailedOut`, when given, tells the two apart -- true means the file is
    // there and could not be read. ICoreStudioSerialization holds autosave off on that,
    // because replaying "nothing" and then autosaving it back is how a project
    // that was perfectly fine gets destroyed by being opened.
    static std::vector<std::string> loadProjectSerializationFromProjectFolder(
        bool* readFailedOut = nullptr);

    // The active project's .iproj path: <documents>/<project>/<project>.iproj.
    static std::filesystem::path projectSerializationFilePath();

    // True when that file is present on disk, whether or not it can be read.
    // This is the "a project file exists here" question, as distinct from "this
    // folder is a project" (ICoreProjectSession::isValidProjectFolder).
    static bool projectSerializationFileExists();

    // True when that file is no longer the one this app last read or wrote: it
    // appeared, disappeared, or its size or modification time moved. Something
    // outside the app changed it -- a coding agent, a text editor, a sync
    // client -- and autosave checks this before writing over it (the
    // agent-bridge board, AB.18). False before this project's file has been
    // read or written.
    static bool projectFileChangedOutsideApp();
    // Mirrors an image into the project's Images subfolder as <pixmapClassId>.<ext>.
    // A no-op when a cached copy already exists under that id: ids are derived
    // from the picture, so the file that is there is already this image.
    static void copyImageToProjectFolder(const std::filesystem::path& originalImagePath, const std::string& pixmapClassId);
    static void loadAllImagesFromProjectFolder_OverwriteCachedInStateMachine();

    // Looks up the cached copy copyImageToProjectFolder() made for a given
    // pixmap cache key (ICoreImageViewPixmap::getPixmapId() / ICoreImageView::
    // getPixmapClassID()) - i.e. a file in the Images subfolder whose stem
    // matches the ID, whatever its original extension was. Returns an empty
    // path if the ID is unknown/"None" or no such file exists (e.g. the
    // project folder was never saved to, or the cached file was removed).
    static std::filesystem::path findCachedImagePath(const std::string& pixmapClassID);

    // A picture chosen for ONE block instance (FEATURES_TO_ADD.md BF22.3):
    // caches it under its content id (ICoreStudioStateMachine::cacheNewPixmap),
    // mirrors it into Images/ with copyImageToProjectFolder(), and answers the
    // path a config stores, relative to the project folder with '/' separators:
    // "Images/<id>.<ext>". Importing the same picture twice answers the same
    // path and writes nothing new. "" when the file is missing or is not a
    // picture ICorePixmap can read, and then nothing is written.
    static std::string importImageIntoProject(const std::filesystem::path& sourceImagePath);

    // The file a stored picture path names: a relative path is taken from the
    // active project folder, an absolute one is answered unchanged, and "" is
    // the empty path. It does not check that the file exists.
    static std::filesystem::path resolveProjectPath(const std::string& storedPath);
};
};

ICoreDocumentsFolder.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ICoreDocumentsFolder.h

ICoreDocumentsFolder#

ICoreDocumentsFolder.h:14 · class · 6 declaration(s)

Two folders with two different jobs, and the names are older than the split: * the DOCUMENTS folder is where the user's projects live -- Documents/<AppName> at startup, then repointed per project b...

class ICoreDocumentsFolder {
public:
    static long initializeDocumentsFolder();
    // static std::vector<std::string> readLogFile();
    // static void overwriteLogFile(const std::vector<std::string>& lines);
    static std::filesystem::path getDocumentsFolderPath();
    // Repoints documentsFolderPath (the parent of the active project). Used by the
    // Project Navigator so getActiveProjectFolderPath() == <this> / projectName.
    static void setDocumentsFolderPath(const std::filesystem::path& folderPath);

    // The per-OS application data folder, assigned once at initialize time:
    // ~/Library/Application Support/<AppName> on macOS,
    // %LOCALAPPDATA%\<AppName> on Windows, $XDG_DATA_HOME/<AppName> elsewhere.
    // Unlike documentsFolderPath (which the navigator repoints per project)
    // this never moves, so navigator state such as recentProjects.txt, the
    // preferences, the template mirror and the user block library live here.
    static std::filesystem::path getApplicationHomeFolderPath();

    static std::filesystem::path getSettingsFilePath();
    static std::filesystem::path getLogFilePath();
};
};

ICoreProjectLock.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ICoreProjectLock.h

ICoreProjectLock#

ICoreProjectLock.h:33 · class · final · 5 declaration(s)

ICoreProjectLock ONE PROJECT, ONE COPY OF THE APP.

class ICoreProjectLock final {
public:
    // Takes `projectFolder` for this process. The previous claim is released
    // only once the new one is held, so a refused claim leaves this process
    // owning exactly what it owned before.
    //
    // False when another process holds it (`whyNot` says which), or when the
    // lock could not be taken for another reason -- an unwritable folder. That
    // second case still returns TRUE when `allowUnlockable` is set: a project
    // on read-only media can be opened, it just cannot be written.
    static bool claim(const std::filesystem::path& projectFolder, std::string* whyNot = nullptr,
                      bool allowUnlockable = true);

    // Gives up this process's claim, if it holds one.
    static void release();

    // The folder this process holds the claim on, or empty. Read by anything
    // that has to put the claim back as it found it -- the regression sandbox.
    [[nodiscard]] static std::filesystem::path claimedFolder();

    // True when this process holds the claim on `projectFolder`.
    [[nodiscard]] static bool isClaimedHere(const std::filesystem::path& projectFolder);

    // True when ANOTHER process holds `projectFolder` right now. `processId`,
    // when given, receives the holder's id if it recorded one. A folder with no
    // lock file, or one this process holds, answers false.
    [[nodiscard]] static bool isHeldElsewhere(const std::filesystem::path& projectFolder,
                                              std::optional<std::int64_t>* processId = nullptr);

    // Runs `write` while this process may write `projectFolder`: at once when
    // it holds the claim, otherwise under a lock taken for the length of the
    // call. Refuses -- `write` never runs, false comes back, `whyNot` says
    // why -- when another process holds the folder.
    static bool withWriteAccess(const std::filesystem::path& projectFolder,
                                const std::function<void()>& write, std::string* whyNot = nullptr);

    // "<name> is open in another ICoreBlocks window (process 4312)." -- the one
    // sentence every refusal uses.
    [[nodiscard]] static std::string heldElsewhereMessage(const std::filesystem::path& projectFolder,
                                                          std::optional<std::int64_t> processId);

    // <project>/.icore/project.lock
    [[nodiscard]] static std::filesystem::path lockFilePath(const std::filesystem::path& projectFolder);

};

ICoreReferencedFiles.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ICoreReferencedFiles.h

ICoreReferencedFiles#

ICoreReferencedFiles.h:56 · class · nested ReadResult · 18 declaration(s)

A REFERENCED subsystem's file (FEATURES_TO_ADD.md BF13.2, owner decision D10).

class ICoreReferencedFiles {
public:
    // The folder new files are suggested in, relative to the project: "References".
    static const char* const kDefaultFolder;

    // A path a Subsystem may name: relative, inside the project folder, ending in
    // ".icore", written with '/', and not under the app's own ".icore/" scratch
    // folder. `why` gets the reason when it is not.
    static bool isValidPath(const std::string& path, std::string* why = nullptr);
    // The form two names of one file share: lexically normal, '/'-separated. Empty
    // for a path isValidPath() refuses.
    static std::string normalize(const std::string& path);
    // The file on disk: the active project folder / `path`.
    static std::filesystem::path resolve(const std::string& path);

    enum class ReadStatus { Read, Missing, Unreadable, InvalidPath, NoProject };
    struct ReadResult {
        ReadStatus status = ReadStatus::Missing;
        std::string recipe;     // the file's text, when Read
        std::string message;    // what went wrong, otherwise
    };
    static ReadResult read(const std::string& path);

    // What write() puts in `path` for `instance`: the source header, then the
    // instance's contents with no model configuration (a referenced subsystem runs
    // under its model's solver), every handle prefixed (handlePrefixFor) and every
    // nested instance written as a reference.
    static std::string fileText(ICoreSubsystemTreeNode* instance, const std::string& path);
    // Writes `instance`'s contents to `path` atomically, making the folders it
    // needs. False, with `error`, when the path is refused or the write fails.
    static bool write(const std::string& path, ICoreSubsystemTreeNode* instance, std::string* error = nullptr);

    // The referenced subsystem `node` sits in: itself, or its nearest ancestor,
    // whose Subsystem block names a file. Null when there is none.
    static ICoreSubsystemTreeNode* instanceOf(ICoreSubsystemTreeNode* node);

    // `node`'s contents changed. When it sits in an instance, that instance's file
    // is edited and the first instance to edit it holds it. False when another
    // instance holds the file: the edit is refused, and the caller takes it back.
    static bool noteEdited(ICoreSubsystemTreeNode* node);
    // Whether an edit inside `node` would reach its file: true outside any
    // instance, and in the instance that holds its file or in one whose file nobody
    // holds. `why` names the holder when it is false.
    static bool mayEdit(ICoreSubsystemTreeNode* node, std::string* why = nullptr);
    static bool isEdited(const std::string& path);
    // The node id (ICoreSubsystemTreeNode::getNodeId) of the instance holding
    // `path`, or 0.
    static std::uint64_t holderOf(const std::string& path);
    // The edited files, normalized, sorted.
    static std::vector<std::string> editedFiles();

    // Writes every edited file from its holder and ends the holds, then creates
    // every file an instance names that does not exist yet, from the first such
    // instance in the model (pre-order). A file whose holder has since been
    // deleted is dropped with a warning. False when any write failed; `error`
    // names each one, and those files stay edited.
    static bool saveEdited(std::string* error = nullptr);

    // An instance whose contents a project or file writes as a path: its
    // Subsystem block names a file isValidPath() accepts.
    static bool savedAsPath(ICoreSubsystemTreeNode* node);
    // What a project save writes: `root` serialized with every instance as a
    // reference (savedAsPath). Identical to ICoreRecipeSerializer::serialize when
    // the model holds no instance.
    static std::string projectText(ICoreSubsystemTreeNode* root);
    // The prefix every handle in `path`'s own text starts with: "rf_", the
    // normalized path as an identifier, "_".
    static std::string handlePrefixFor(const std::string& path);
    // `text` with every reference marker pair replaced by its file's contents,
    // retargeted at the instance's handle, nested references expanded too. A pair
    // whose file cannot be used is left as it is (its gates replay) and named in
    // `problems`.
    static std::string expand(const std::string& text, std::vector<std::string>* problems = nullptr);
    // Ends every hold and forgets every edit, unsaved ones included: a project was
    // loaded or replaced, and the node ids the holds were keyed by are gone.
    static void forget();
};
};

ICoreVariantAssembly.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ICoreVariantAssembly.h

ICoreVariantAssembly#

ICoreVariantAssembly.h:39 · class · nested Result · 2 declaration(s)

A VARIANT ASSEMBLY SUBSYSTEM's choices, made from its files (the owner's option 1, 2026-10-02).

class ICoreVariantAssembly {
public:
    struct Result {
        bool changed = false;              // the model was edited
        std::vector<std::string> problems; // refusals, one line each
    };

    // Makes `face`'s choices match its specifier. Nothing for a face that is not an
    // assembly.
    static Result sync(ICoreBlock* face);
    // The same for every assembly in the model, outermost first.
    static Result syncAll();
};
};

ICoreProjectCard.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ProjectNavigator/ICoreProjectCard.h

ICoreProjectCard#

ICoreProjectCard.h:30 · class · bases public ICoreWidget · pImpl · 13 declaration(s)

ICoreProjectCard One row of the Project Navigator's recents list: the project's name, the folder it lives in, and a remove affordance that appears under the pointer.

class ICoreProjectCard : public ICoreWidget {
public:
    ICoreProjectCard(ICoreWidget* parent, const std::filesystem::path& projectFolderPath);
    ~ICoreProjectCard() override;

    [[nodiscard]] const std::filesystem::path& projectFolderPath() const;

    // Lowercased "<name> <parent path>", for the list's filter field.
    [[nodiscard]] const ICoreString& searchKey() const;

    // A folder that no longer holds its <name>.iproj still gets a row -- greyed,
    // labelled, and still removable -- rather than silently vanishing from a
    // list the user is looking at.
    void setProjectMissing(bool missing);

    [[nodiscard]] double hoverProgress() const;
    void setHoverProgress(double progress);

    ICoreSignal<> activated;
    ICoreSignal<> removeRequested;

protected:
    void paintContent(ICorePainter& painter) override;
    void pointerEntered() override;
    void pointerLeft() override;
    bool mouseMoved(const ICoreMouseEvent& event) override;
    bool mouseReleased(const ICoreMouseEvent& event) override;
    bool keyPressed(const ICoreKeyEvent& event) override;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreProjectNavigator.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ProjectNavigator/ICoreProjectNavigator.h

ICoreProjectNavigator#

ICoreProjectNavigator.h:40 · class · bases public ICoreWindow · pImpl · 4 declaration(s)

ICoreProjectNavigator The app's entry window: create a project, open one, or pick up a recent one.

class ICoreProjectNavigator : public ICoreWindow {
public:
    explicit ICoreProjectNavigator(ICoreWidget* parent = nullptr);
    ~ICoreProjectNavigator() override;

    // Opens the launcher straight on the new-project form rather than on the
    // recents list -- what "New Project..." elsewhere in the app asks for.
    void showNewProjectForm();

protected:
    // Escape backs out of the new-project form, and closes the launcher from the
    // recents list.
    bool keyPressed(const ICoreKeyEvent& event) override;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreProjectSession.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ProjectNavigator/ICoreProjectSession.h

ICoreProjectSession#

ICoreProjectSession.h:30 · class · final · nested ReloadResult · 7 declaration(s)

ICoreProjectSession Which project the app is in, and the one way to change it.

class ICoreProjectSession final {
public:
    static ICoreProjectSession& instance();

    // What became of a requested switch. Callers care about more than pass/fail:
    // the launcher closes on Switched and AlreadyOpen, stays open on Failed so
    // another project can be picked, and leaves everything alone on Cancelled.
    enum class SwitchOutcome {
        Switched,      // the project is now the open one
        AlreadyOpen,   // it already was; nothing was reloaded
        Cancelled,     // the user backed out, or the folder could not be used
        Failed         // it could not be replayed; the editor is empty and autosave is held off
    };

    // Points the app at `projectFolderPath` and loads it. With createIfMissing
    // the folder is created and given an empty .iproj first (New Project);
    // otherwise it must already be a project folder.
    //
    // Claims the project for this process first (ICoreProjectLock) and refuses
    // -- Cancelled, with a box saying which process has it -- a project another
    // copy of the app holds. The claim is kept until the next switch.
    static SwitchOutcome switchToProjectFolder(ICoreNativeWidget* dialogParent,
                                               const std::filesystem::path& projectFolderPath,
                                               bool createIfMissing);

    // Persists -- or asks about -- the project currently in the editor, before it
    // is replaced. Returns false when the user cancels, which aborts the switch.
    static bool commitCurrentProject(ICoreNativeWidget* dialogParent);

    // True when folderPath/<folderName>.iproj exists (the project's serialized
    // file). This is the whole definition of "is a project folder", and startup
    // asks it too, before reopening the last project without a navigator.
    static bool isValidProjectFolder(const std::filesystem::path& folderPath);

    // What reloadFromFolder() did.
    struct ReloadResult {
        bool ok = false;                     // the project file replayed in full
        std::string error;                   // why it did not reload, or did not load in full
        std::vector<std::string> problems;   // lines that did not apply, "<line>: <why>"
        std::string backupFile;              // what was on screen before, written here
    };

    // Re-reads the OPEN project from its own folder -- the .iproj and its
    // sidecars -- replacing what is on screen. It is the trigger a coding agent
    // pulls after editing the project's files in place (the agent-bridge board,
    // AB.17), and Reload from Project Folder in the project menu.
    //
    // What was on screen is first written to <project>/.icore/before-reload.iproj,
    // so an edit made in the app since the last save is never simply gone.
    // Refused, with `error` set and nothing touched, while no project is open,
    // the project file is missing, a Script IDE run is live, or code export has
    // the model frozen. Undo history does not survive it, as it survives no load.
    // A file that does not replay in full leaves autosave off, exactly as opening
    // it would (ICoreStudioSerialization::didLastProjectLoadFail).
    static ReloadResult reloadFromFolder();

    // ---- a project in a NEW WINDOW ------------------------------------------
    //
    // ⚠ A NEW WINDOW IS A NEW PROCESS. Everything a project is -- the two
    // project statics, the subsystem tree, the state machine, the workspace,
    // the solver -- is process-wide, and an editor window in this process is a
    // view onto that one project (ICoreStudioRegistry::requestNewEditorWindow).
    // So "open in a new window" starts another copy of this binary, told by a
    // switch what to open, and leaves this process's project untouched: no
    // save prompt, no switch, nothing refused while a script or export runs.
    //
    // The switches the child is started with. Initialization reads them at
    // startup, ahead of the startup preference:
    //   --project <folder>   open that project instead of the most recent one
    //   --new-project        come up on the launcher's New Project form
    static constexpr const char* kOpenProjectSwitch = "--project";
    static constexpr const char* kNewProjectSwitch  = "--new-project";

    // False where this build cannot start another copy of itself (web, iOS,
    // Android). The menus offer the new-window rows only when this is true.
    [[nodiscard]] static bool canOpenInNewWindow();

    // Starts another copy of the app on `projectFolderPath`. Refuses, saying why
    // in a box on `dialogParent`, a folder that is not a project, the project
    // already open HERE, and a project another copy holds (ICoreProjectLock) --
    // two processes saving one project would overwrite each other's edits.
    // Returns whether a process was started.
    static bool openInNewWindow(ICoreNativeWidget* dialogParent,
                                const std::filesystem::path& projectFolderPath);

    // Asks for a project folder, then openInNewWindow() on it. Cancelling the
    // picker does nothing.
    static void chooseAndOpenInNewWindow(ICoreNativeWidget* dialogParent);

    // Starts another copy of the app on the New Project form; the project is
    // named and created there, in the new window.
    static bool newProjectInNewWindow(ICoreNativeWidget* dialogParent);

    // The app is now in a different project, loaded and recorded as recent.
    // Raised synchronously, at the end of a successful switch.
    ICoreSignal<> onProjectChanged;

};

ICoreRecentProjects.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ProjectNavigator/ICoreRecentProjects.h

ICoreRecentProjects#

ICoreRecentProjects.h:17 · class · 5 declaration(s)

ICoreRecentProjects Tiny persistence helper for the Project Navigator's "Recent Projects" list.

class ICoreRecentProjects {
public:
    // Most-recent first. Missing/deleted folders are filtered out on read.
    static std::vector<std::filesystem::path> getRecentProjects();

    // Promotes the path to the front (de-duplicated) and trims to the user's
    // configured maximum.
    static void addRecentProject(const std::filesystem::path& projectFolderPath);

    // Drops one entry from the list. This forgets the project, it does not touch
    // the folder on disk -- it is what the navigator's per-card remove does.
    static void removeRecentProject(const std::filesystem::path& projectFolderPath);

    static void clearRecentProjects();

    // Where the list is kept: <application home>/recentProjects.txt. Public so
    // that anything which has to leave this file exactly as it found it -- the
    // regression suite backs it up and restores it, because the application home
    // folder is deliberately NOT sandboxed -- can name it without restating the
    // filename somewhere else.
    static std::filesystem::path recentProjectsFilePath();
};
};

ICoreTemplateCard.h#

src/ICoreBlocks/ICoreStudio/ExternalCommunications/ProjectNavigator/ICoreTemplateCard.h

ICoreTemplateCard#

ICoreTemplateCard.h:40 · class · bases public ICoreWidget · pImpl · 12 declaration(s)

ICoreTemplateCard One choice in a "start from" gallery: a picture of the diagram, its name, and a sentence saying what it is for.

class ICoreTemplateCard : public ICoreWidget {
public:
    // A template. The recipe is read once, here, to draw the thumbnail.
    //
    // The parent is an ICoreAnyWidget: ICoreNewTabPanel holds its gallery
    // container as a plain widget pointer and hands it in, so it cannot narrow
    // to ICoreWidget*.
    ICoreTemplateCard(ICoreNativeWidget* parent, const ICoreTemplateLibrary::Entry& entry);

    // The "start from nothing" choice: the same card with no template behind it,
    // so blank sits in the gallery as a peer of the templates rather than as a
    // checkbox somewhere else in the form. Its wording is the caller's, because
    // what "blank" produces differs by gallery -- an empty project on one, an
    // empty subsystem on the other.
    static ICoreTemplateCard* makeBlankCard(ICoreNativeWidget* parent, const ICoreString& title,
                                            const ICoreString& summary);

    // Empty for the blank card; otherwise the entry's id.
    [[nodiscard]] ICoreString templateId() const;

    // Everything about the card a gallery's filter field should match on, folded
    // to lower case once here rather than on every keystroke: what is written on
    // the card, plus the category and id, which are not drawn but are how a user
    // who knows the catalog would think to search it.
    [[nodiscard]] const ICoreString& searchKey() const;

    [[nodiscard]] bool isSelected() const;
    void setSelected(bool selected);

    [[nodiscard]] double hoverProgress() const;
    void setHoverProgress(double progress);

    // The user picked this card. The gallery deselects its siblings; a card
    // never assumes it won.
    ICoreSignal<> chosen;

protected:
    void paintContent(ICorePainter& painter) override;
    void pointerEntered() override;
    void pointerLeft() override;
    bool mouseReleased(const ICoreMouseEvent& event) override;
    bool keyPressed(const ICoreKeyEvent& event) override;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};