Class Avatar

java.lang.Object
limn.scene.Widget<Avatar>
limn.components.Avatar

public final class Avatar extends Widget<Avatar>
A person, drawn as a circle: their picture when there is one, and otherwise their initials over a colour of their own. An assignee in a table's column, the user on a tool bar, a contact's row.

The size is the control height of the step (32 points at MEDIUM), so an avatar sits in a row of controls at their height; give it a SizedBox for a larger one, and the circle fills the smaller side of the box it is given. A box squeezed to a point or so across draws the tinted circle without its letters, and one of no size draws nothing.

The colour is one of the chart palette's categorical colours (ChartPalette.defaultFor(Theme)), chosen by the name's String.hashCode(), mixed, unless setColorIndex(int) says which, so the same name has the same colour on every run and every machine. Categorical, and never a state's tone: a person drawn in the danger colour reads as an error. It is drawn as a tint, at 22 % (34 % in a dark palette), with the initials in the palette's text colour, so their contrast is the palette's own text on its surface.

The initials, unless setInitials(java.lang.String) gives them, are the first grapheme of the name's first word and of its last, upper-cased in the avatar's locale: "Ana Lima" is "AL", "Ana" is "A", an accent or a joined emoji is kept whole, and a script without case stays as it is. With neither initials nor a picture, a silhouette of a head and shoulders is drawn.

To a reader an avatar is an image named by the person, so one standing alone (a user button's picture, a column of owners) is read. Beside the name it repeats, as in a contact's row, take it out with setAccessibleIgnored(true). Inside an AvatarGroup it is not published at all: the group is one node described by every name.


 new Avatar("Ana Lima");
 new Avatar("Rui Costa").setImage(photo);
 
  • Constructor Details

    • Avatar

      public Avatar(String name)
      An avatar for a person with a fixed name.
      Parameters:
      name - the person's name; never null
    • Avatar

      public Avatar(I18nString name)
      An avatar whose name follows the UI language, for a name that is a role ("Support").
      Parameters:
      name - the person's name; never null
  • Method Details

    • setName

      public Avatar setName(String newName)
      Replaces the name: the initials, the colour and what a reader hears follow it.
      Parameters:
      newName - the name; never null
      Returns:
      this avatar
    • setName

      public Avatar setName(I18nString newName)
      Replaces the name with one that follows the UI language.
      Parameters:
      newName - the name; never null
      Returns:
      this avatar
    • name

      public String name()
      Returns:
      the person's name, in the language in effect
    • setInitials

      public Avatar setInitials(@Nullable String value)
      Gives the initials instead of deriving them from the name; null derives them again.
      Parameters:
      value - the initials, drawn as given; or null
      Returns:
      this avatar
    • setImage

      public Avatar setImage(@Nullable Image newImage)
      Sets the person's picture, drawn covering the circle and clipped to it; null brings the initials back. An animated image is drawn at its first frame.
      Parameters:
      newImage - the picture, or null
      Returns:
      this avatar
    • image

      public @Nullable Image image()
      Returns:
      the picture, or null
    • setColorIndex

      public Avatar setColorIndex(int index)
      Chooses the palette colour by its index instead of by the name, for two people whose names fall on the same colour side by side. Indexes past the palette's size repeat it.
      Parameters:
      index - the index, at least zero
      Returns:
      this avatar
      Throws:
      IllegalArgumentException - if index is negative
    • colorIndex

      public int colorIndex()
      The palette index the avatar is drawn in: the one given, or the name's hash modulo the palette's size.
      Returns:
      the index
    • paintOutset

      protected float paintOutset()
      Description copied from class: Widget
      How far beyond this widget's bounds its painting may reach, in logical points: its own painting and any descendant no ancestor clips (a drop shadow, a glow, a child positioned outside the parent's box). Partial rendering uses it both ways: Widget.invalidate() damage grows by it, and a repaint pass skips this subtree only when bounds + outset miss the pass region; painting farther than declared leaves stale pixels.

      The work is divided by who knows the number. A widget declares what it paints itself outside its box: Label's icon overhang, the focus ring Button, Checkbox and RadioButton draw outside theirs. A widget that lays out children and does not clip them declares how far they may paint past it, because a ring on a child at its edge hangs past it too, and a pass landing only in that band would otherwise skip it and never reach the child. Every layout the toolkit ships does that by default with the reach the theme gives a focus ring, and takes another number through its public paintOverflow, which sets what this hook answers; a layout an application writes inherits both by extending limn.scene.layout.Container, and one that extends this class directly overrides this hook itself. A widget that clips its children declares only its own painting, since the clip bounds theirs.

      Asked of every widget a repaint pass considers, and on every invalidate(), so an override answers in constant time without allocating: a number held or looked up, never a walk over the children. Default 0: everything stays inside the bounds, which is true for most leaves.

      Overrides:
      paintOutset in class Widget<Avatar>
    • onMeasure

      protected Size onMeasure(Constraints constraints)
      Description copied from class: Widget
      Reports the size this widget wants within constraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.

      Resolve the ControlSize and the LayoutDirection once each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, and I18n.locale() answers it wherever text is resolved.

      Specified by:
      onMeasure in class Widget<Avatar>
    • onPaint

      protected void onPaint(Canvas canvas)
      Description copied from class: Widget
      Widget's own background/content, in local coordinates.
      Overrides:
      onPaint in class Widget<Avatar>
    • onAccessibility

      protected void onAccessibility(Accessibility a)
      One Accessible.Role.IMAGE named by the person. The name is the held string by reference, so a frame that repaints the avatar compares it without allocating.

      Its provenance is Accessible.NameFrom.EXPLICIT, not content: the circle paints initials or a picture and never the name, so the name is text about the image, which macOS publishes as AXDescription, the attribute VoiceOver reads for a picture.

      Overrides:
      onAccessibility in class Widget<Avatar>
      Parameters:
      a - the node being described