
// // Copyright (c) 2008, Brian Frank and Andy Frank // Licensed under the Academic Free License version 3.0 // // History: // 10 Jun 08 Brian Frank Creation // // // TODO: // Widgets: // - SashPane (weights?) // - ScrollPane // - BorderPane // - StyledText // - ProgressBar // - Dialogs // - FileDialog // - DirDialog // Eventing // - ids // - mouse eventing // - key eventing // Graphics: // - clipping // - affine transformations // - font metrics // Text: // - caret positioning // - selection // - eventing // Peers: // - update sync model (font won't work right) // ** ** Widget is the base class for all UI widgets. ** @serializable @collection abstract class Widget { ////////////////////////////////////////////////////////////////////////// // Fields ////////////////////////////////////////////////////////////////////////// ** ** Enabled is used to control whether this widget can ** accept user input. Disabled controls are "grayed out". ** native Bool enabled ** ** Controls whether this widget is visible or hidden. ** native Bool visible ////////////////////////////////////////////////////////////////////////// // Bounds ////////////////////////////////////////////////////////////////////////// ** ** Position of this widget relative to its parent. ** If this a window, this is the position on the screen. ** @transient native Point pos ** ** Size of this widget. ** @transient native Size size ** ** Position and size of this widget relative to its parent. ** If this a window, this is the position on the screen. ** native Rect bounds ** ** Get the position of this widget on the screen coordinate's ** system. If not on mounted on the screen then return null. ** native Point posOnDisplay() ////////////////////////////////////////////////////////////////////////// // Widget Tree ////////////////////////////////////////////////////////////////////////// ** ** Get this widget's parent or null if not mounted. ** @transient readonly Widget parent ** ** Get this widget's parent window or null if not ** mounted under a Window widget. ** Window window() { x := this while (x != null) { if (x is Window) return (Window)x x = x.parent } return null } ** ** Iterate the children widgets. ** Void each(|Widget w, Int i| f) { kids.each(f) } ** ** Get the children widgets. ** Widget[] children() { return kids.ro } ** ** Add a child widget. If child is null, then do nothing. ** If child is already parented throw ArgErr. Return this. ** virtual This add(Widget child) { if (child == null) return this if (child.parent != null) throw ArgErr("Child already parented: $child") child.parent = this kids.add(child) child.attach return this } ** ** Remove a child widget. If child is null, then do ** nothing. If this widget is not the child's current ** parent throw ArgErr. Return this. ** virtual This remove(Widget child) { if (child == null) return this child.detach if (kids.removeSame(child) == null) throw ArgErr("not my child: $child") return this } ** ** Remove all child widgets. Return this. ** virtual This removeAll() { kids.dup.each |Widget kid| { remove(kid) } return this } ////////////////////////////////////////////////////////////////////////// // Layout ////////////////////////////////////////////////////////////////////////// ** ** Relayout this widget. This method is called when something ** has changed and we need to recompute the layout of this ** widget's children. ** Void relayout() { send(relayoutId, null) } internal const static Str relayoutId := "relayout" ** ** Compute the preferred size of this widget. The hints indicate ** constraints the widget should consider in its calculations. ** If no constraints are known for width, then 'hints.w' will be ** null. If no constraints are known for height, then 'hints.h' ** will be null. ** virtual native Size prefSize(Hints hints := Hints.def) ** ** Handle the layout event. The method is only called Pane ** containers. Custom panes must override this method to ** set the bounds on all their children. ** virtual Void onLayout() {} ////////////////////////////////////////////////////////////////////////// // Painting ////////////////////////////////////////////////////////////////////////// ** ** Repaint this widget. If the dirty rectangle is null, ** then the whole widget is repainted. ** Void repaint(Rect dirty := null) { send(repaintId, null) } internal const static Str repaintId := "repaint" ** ** This callback is invoked when the widget should be repainted. ** The graphics context is initialized at the widget's origin ** with the clip bounds set to the widget's size. ** virtual Void onPaint(Graphics g) { } ////////////////////////////////////////////////////////////////////////// // Peer ////////////////////////////////////////////////////////////////////////// ** Is this widget attached to a native peer? private native Bool attached() ** Attach to a native peer private native Void attach() ** Detach from native peer private native Void detach() ** Sync the specified field to the native widget internal native Void sync(Str field) ** Send the native widget peer a message internal native Obj send(Str name, Obj arg) ////////////////////////////////////////////////////////////////////////// // Private ////////////////////////////////////////////////////////////////////////// @transient internal Widget[] kids := Widget[,] }