Class Diagram¶
A non-exhaustive map of the main types in Turbo Vision for Rust and how they fit
together. Borland's deep inheritance tree becomes a single View trait plus
composition: a Window owns a Frame and an interior Group, a Dialog
wraps a Window, and the Desktop keeps its windows in a Group. Specialised
behaviour lives in small extension traits (Cluster, ListViewer,
MenuViewer, Editor) that require View.
classDiagram
direction TB
class View {
<<trait>>
+bounds() Rect
+set_bounds(Rect)
+draw(Terminal)
+handle_event(Event)
+can_focus() bool
+set_focus(bool)
+state() StateFlags
+options() u16
+grow_mode() GrowFlags
}
class IdleView {
<<trait>>
+idle()
}
class Cluster {
<<trait>>
+cluster_state()
}
class ListViewer {
<<trait>>
+list_state()
+item_count() usize
}
class MenuViewer {
<<trait>>
+menu_state()
}
class Editor {
<<trait>>
+undo()
+redo()
+cut() bool
+copy() bool
+paste() bool
}
class FileEditor {
<<trait>>
+load(PathBuf)
+save()
+save_as(PathBuf)
}
View <|-- IdleView
View <|-- Cluster
View <|-- ListViewer
View <|-- MenuViewer
View <|-- Editor
Editor <|-- FileEditor
class Application {
+terminal: Terminal
+desktop: Desktop
+menu_bar: Option~MenuBar~
+status_line: Option~StatusLine~
+running: bool
+run()
+handle_event(Event)
}
class Desktop {
-children: Group
+add(Box~View~)
+cascade()
+tile()
+bring_to_front(ViewId)
}
class Group {
-children: Vec~Box~View~~
-focused: usize
-end_state: CommandId
+add(Box~View~) ViewId
+execute() CommandId
+end_modal(CommandId)
+broadcast(Event, owner)
}
class Window {
-frame: Frame
-interior: Group
-number: Option~u8~
-zoom_rect: Rect
+add(Box~View~) ViewId
+zoom(Rect)
}
class Frame {
-title: String
-resizable: bool
-zoomable: bool
+is_zoomed() bool
}
class Dialog {
-window: Window
-result: CommandId
+execute(Application) CommandId
}
class MenuBar {
-submenus: Vec~SubMenu~
}
class MenuBox
class StatusLine {
-items: Vec~StatusItem~
}
class Button {
-title: String
-command: CommandId
-is_default: bool
}
class InputLine
class StaticText
class Label
class CheckBox
class RadioButton
class ListBox
class ScrollBar
class Scroller
class TextViewer
class Memo
class EditorWindow
class FileEditorWindow
class Event {
+what: EventType
+key_code: u16
+mouse: MouseEvent
+command: CommandId
+clear()
}
class Terminal {
+put_event(Event)
+flush()
}
class Rect
class Palette
Application *-- Desktop
Application *-- Terminal
Application o-- MenuBar
Application o-- StatusLine
Desktop *-- Group
Window *-- Frame
Window *-- Group : interior
Dialog *-- Window
Group o-- "0..*" View : children
Scroller o-- ScrollBar
TextViewer o-- ScrollBar
MenuBar ..> MenuBox : opens
View <|.. Desktop
View <|.. Group
View <|.. Window
View <|.. Frame
View <|.. Dialog
View <|.. MenuBar
View <|.. StatusLine
View <|.. Button
View <|.. InputLine
View <|.. StaticText
View <|.. Label
View <|.. ScrollBar
View <|.. Scroller
View <|.. TextViewer
View <|.. Memo
Cluster <|.. CheckBox
Cluster <|.. RadioButton
ListViewer <|.. ListBox
MenuViewer <|.. MenuBar
MenuViewer <|.. MenuBox
Editor <|.. EditorWindow
FileEditor <|.. FileEditorWindow
View ..> Event : handles
View ..> Terminal : draws to
View ..> Rect : bounds
View ..> Palette : colours from
Reading the diagram¶
Solid arrows with a hollow head between traits mean a supertrait bound, so
Cluster: View. Dashed arrows with a hollow head mean a struct implements the
trait. Filled diamonds are ownership by value, hollow diamonds are optional or
boxed ownership.
Two things differ from the Borland original and are worth noticing here.
First, there is no TProgram and TApplication pair: Application owns the
Desktop, MenuBar and StatusLine directly and drives the event loop.
Second, modality lives in Group::execute, which runs a nested loop until
end_modal sets end_state. Dialog::execute simply delegates to the group
inside its window and reports the resulting command.
For the full widget list see the crate documentation, and for the rationale behind the composition-based design see Chapter 7: Architecture Overview and MISSING-INHERITANCE.md.