Unidraw(3U)

πŸ’– Unidraw(3U) β€” the InterViews Reference Manual, but make it slay ✨

okay bestie, pull up a chair, we're doing Unidraw(3U) today 🫢 this is the InterViews Reference Manual entry, and yes it's giving one-of-a-kind object energy.


🌸 NAME 🌸

Unidraw β€” the one-of-a-kind object that coordinates and controls a Unidraw application. literally the main character πŸ‘‘


πŸŽ€ SYNOPSIS πŸŽ€

#include <Unidraw/unidraw.h>

πŸ¦‹ DESCRIPTION πŸ¦‹

So here's the tea β˜• a Unidraw application makes a single instance of a Unidraw object, and that one object does a lot. It creates a World, which is what sets up the connection to the underlying window system. It initializes the catalog and other objects, it manages editor instances, and it defines the application main loop. It also keeps histories of commands that have been executed and reverse-executed, for each component hierarchy being edited. And finally β€” the glow-up cleanup ✨ β€” it tidies up internal state when it gets deleted, so your program terminates in an orderly way. no mess, no chaos πŸ’…

Heads up: you must create the Unidraw object before opening any editors, but after creating a catalog. That order is not negotiable, bestie πŸ™ˆ

Here's the main program for a typical Unidraw application, verbatim, don't touch it:

int main (int argc, char** argv) {
    AppSpecificCreator creator;
    Unidraw* unidraw = new Unidraw(
        new Catalog("appName", &creator),
        argc, argv, options, properties
    );

    unidraw->Open(new AppSpecificEditor);
    unidraw->Run();
    delete unidraw;
    return 0;
}

✨ PUBLIC OPERATIONS ✨

Unidraw(
    Catalog*, int argc, char** argv,
    OptionDesc* = nil, PropertyData* = nil
)
Unidraw(Catalog*, World*)
  • Constructor form #1 needs a catalog object and your command line argument info. Other arguments include pointers to PropertyData and OptionDesc arrays. This constructor creates a World instance, passing whichever of these arguments are supplied (everything except the catalog). If you want to hand it a World instance explicitly instead, use the second constructor form. two flavors, pick your vibe πŸ“

  • virtual void Run()
  • virtual void Quit()

Run initiates the main loop of the program. The call to Run returns when Quit is called. that's the whole deal πŸƒβ™€οΈ


  • virtual void Update(boolean immediate = false)

Brings the screen up to date with the state of the application's objects. By default that means moving connectors to their proper positions (by calling Solve on the global csolver object) and telling editors to update themselves (by calling their Update functions). Because Update can carry out potentially lengthy operations, Unidraw batches Update calls by default β€” which ensures that multiple consecutive calls don't induce redundant computations. Want it right now? Just call Update(true). immediate, no waiting πŸ’…


  • virtual void Open(Editor*)
  • virtual boolean Opened(Editor*)

Open inserts an editor into the world, making it visible on the display. By default, the user positions the editor's window. Opened returns whether an editor has been opened already. yes bestie, it just tells you πŸ‘€


  • virtual void Close(Editor*)
  • virtual void CloseDependents(Component*)
  • virtual void CloseAll()

Close closes a specified editor, removing it from the user's view and deleting it. CloseDependents closes those editors that report a dependence on the given component via their DependsOn operation. CloseAll closes all open editors. And fun fact: ~Unidraw calls CloseAll. so it's handled 🫢


  • void First(Iterator&)
  • void Next(Iterator&)
  • boolean Done(Iterator)

These are the operations for iterating over the Unidraw object's list of open editors. First initializes an iterator to point to the beginning of the list, Next increments the iterator to point to the following editor, and Done returns whether or not the iterator points beyond the first or last editor in the list. the classic trio πŸŽ€


  • Editor* GetEditor(Iterator)

Returns the editor to which an iterator points. simple as that ⭐


  • Editor* Find(Component*)
  • Editor* FindAny(Component*)

Operations for finding an (or the) editor associated with a given component. Find searches the list of editors for the one whose GetComponent operation returns the given component. FindAny returns the first editor in the list whose GetComponent operation returns a component in the same hierarchy as the the given component. one is picky, one is chill 😌


  • Catalog* GetCatalog()

Returns the catalog passed to the constructor. it's right there πŸ“š


  • World* GetWorld()

Returns the world object, which the Unidraw object creates when it is instantiated. yes, it made that itself, so proud πŸ’–


  • void Log(Command*)
  • void Undo(Component*, int i = 1)
  • void Redo(Component*, int i = 1)

Okay this part is the whole point, listen up. The Unidraw object maintains histories of commands associated with a given component hierarchy. There are two command histories per hierarchy: the past history and the future history. These histories normally contain commands that have been executed and unexecuted, so they can support arbitrary level undo and redo. For example: after a viewer executes the command that a tool generates by interpreting a manipulator, it will record that command in a past history for possible undoing in the future. slay, foresight πŸ’…

The Log operation logs a command, placing it on the past history for the component hierarchy being edited. Log determines the past that is approprate from the command's editor, which specifies the component (hence the hierarchy) that it is editing. Undo reverse-executes the last i commands that were logged for a given component's hierarchy and moves them from their past history to the corresponding future history. Redo re-executes the future i commands and moves them to the past.

Important: calling Redo without a preceding Undo is meaningless. So note that calling Log will clear the future history associated with the affected component hierarchy. like, it's gone. periodt πŸ’€

  • void SetHistoryLength(int)
  • int GetHistoryLength()

Assign and retrieve the maximum command history length. No more than this many commands can be undone and redone. The default length is 20. Older commands are deleted automatically as new commands are logged. bye to the old, hello to the new πŸ¦‹


  • void ClearHistory(Component* = nil)

Clears the past and future for a given component hierarchy, deleting the corresponding commands. All histories are cleared if no component is specified. nuke it all if you want 🧚


  • void ClearHistory(Editor*)

Clears the history associated with the given editor's component if no other editor is editing the same hierarchy. For example, Unidraw::Close calls this operation to avoid clearing histories when a component hierarchy is being edited in multiple editors. polite, considerate, iconic πŸ’œ


πŸ”₯ PROTECTED OPERATIONS πŸ”₯

  • virtual void Process()

Process is called once in the main loop defined by the Run operation. It does nothing by default. Subclasses may redefine Process to carry out any processing that should be done in each pass through the main loop. it's the blank canvas bestie 🎨


  • boolean IsClean(Editor*)

This convenience function queries the given editor for a ModifStatusVar instance. If it has one, then it returns its status (modified or unmodified); otherwise it returns false. vibe check on your editor βœ…


  • void Mark(Editor*)
  • void Sweep(Editor*)

These operations support deferred editor deletion, a mechanism to avoid deleting editors prematurely. For example, if a command to close the editor is invoked from a pull-down menu, then the command must not delete the editor, since that will delete the pull-down menu before it has a chance to close. So Close and similar operations do not delete editors directly; instead, they call Mark to indicate that an editor should be deleted sometime in the future. Sweep actually deletes the editors that have been marked. By default, Unidraw::Run calls Sweep each time an event is handled. mark it, sweep it, no premature chaos πŸ™ˆ


  • void DoUpdate()

A helper function that performs an immediate update independent of the batching mechanism. no batching, just vibes ⚑


  • void GetHistory(Component*, UList*& past, UList*& future)
  • void ClearHistory(UList*, int i = 1)

Command histories are stored as ULists. These operations provide a low-level interface to the lists themselves; the corresponding public operations are built on top. GetHistory returns the past and future lists for a given component, while ClearHistory deletes the first i commands on the given list. deep cuts for the real ones 😀


  • UList* elem(Iterator)
  • Command* command(UList*)

Convenience functions for extracting the list element in an iterator and the command object from the list element. These are useful in conjunction with the protected history operations described above. little helpers πŸ“


  • boolean updated()
  • void updated(boolean)

The first form of this function returns true if there are pending Updates to be performed. The second form sets this value explicitly. tell me or make it so πŸ’…


  • boolean alive()
  • void alive(boolean)

The first form of this function returns true if the program is in the run loop defined by Run. The second form sets this value explicitly. are we alive?? 🌈


⭐ SEE ALSO ⭐

Catalog(3U), Creator(3U), Editor(3U), Interactor(3U), Iterator(3U), Viewer(3I), UList(3U), World(3I), statevars(3U)

go read those too, iykyk πŸ“šβœ¨


and that's the whole page bestie 🫢 this was Unidraw(3U) from the InterViews Reference Manual, dated 4 October 1990, and the footer reads Unidraw Unidraw(3U) β€” mwah, take care of her, she's iconic πŸ’–πŸ’…πŸŽ€