...

Source file src/code.rocket9labs.com/tslocum/etk/window.go

Documentation: code.rocket9labs.com/tslocum/etk

     1  package etk
     2  
     3  import (
     4  	"fmt"
     5  	"image"
     6  
     7  	"github.com/hajimehoshi/ebiten/v2"
     8  	"github.com/hajimehoshi/ebiten/v2/text/v2"
     9  )
    10  
    11  // Window displays a single child widget at a time, and includes a list to
    12  // view other child widgets. Window.Show must be called after adding a widget.
    13  type Window struct {
    14  	*Box
    15  	font         *text.GoTextFaceSource
    16  	fontSize     int
    17  	frameSize    int
    18  	list         *List
    19  	listH        Alignment
    20  	listV        Alignment
    21  	listSize     int
    22  	listWidget   *WithoutFocus
    23  	defaultFocus []Widget
    24  	labels       []string
    25  	active       int
    26  	modified     bool
    27  	listModified bool
    28  	firstDraw    bool
    29  }
    30  
    31  // NewWindow returns a new Window widget.
    32  func NewWindow() *Window {
    33  	w := &Window{
    34  		Box:       NewBox(),
    35  		font:      Style.TextFont,
    36  		fontSize:  Scale(Style.TextSize),
    37  		frameSize: Scale(4),
    38  		listSize:  Scale(172),
    39  		listH:     AlignEnd,
    40  		listV:     AlignCenter,
    41  		active:    -1,
    42  		firstDraw: true,
    43  	}
    44  	w.list = NewList(int(float64(Scale(Style.TextSize))*1.5), w.selectItem)
    45  	w.listWidget = &WithoutFocus{w.list}
    46  	return w
    47  }
    48  
    49  // SetRect sets the position and size of the widget.
    50  func (w *Window) SetRect(r image.Rectangle) {
    51  	w.Lock()
    52  	defer w.Unlock()
    53  
    54  	w.rect = r
    55  	w.modified = true
    56  }
    57  
    58  // Clip returns whether the widget and its children are restricted to drawing
    59  // within the widget's rect area of the screen. For best performance, Clip
    60  // should return false unless clipping is actually needed.
    61  func (w *Window) Clip() bool {
    62  	return false
    63  }
    64  
    65  // SetFont sets the font and text size of the window titles. Scaling is not applied.
    66  func (w *Window) SetFont(fnt *text.GoTextFaceSource, size int) {
    67  	w.Lock()
    68  	defer w.Unlock()
    69  
    70  	w.font = fnt
    71  	w.fontSize = size
    72  	w.list.SetItemHeight(size)
    73  }
    74  
    75  // SetFrameSize sets the size of the frame around each window.
    76  func (w *Window) SetFrameSize(size int) {
    77  	w.Lock()
    78  	defer w.Unlock()
    79  
    80  	w.frameSize = size
    81  	w.modified = true
    82  }
    83  
    84  // SetListSize sets the width or height of the window tab list.
    85  func (w *Window) SetListSize(size int) {
    86  	w.Lock()
    87  	defer w.Unlock()
    88  
    89  	w.listSize = size
    90  	w.modified = true
    91  }
    92  
    93  // SetListHorizontal sets the horizontal alignment of the window tab list.
    94  func (w *Window) SetListHorizontal(h Alignment) {
    95  	w.Lock()
    96  	defer w.Unlock()
    97  
    98  	w.listH = h
    99  	w.modified = true
   100  }
   101  
   102  // SetListVertical sets the vertical alignment of the window tab list.
   103  func (w *Window) SetListVertical(v Alignment) {
   104  	w.Lock()
   105  	defer w.Unlock()
   106  
   107  	w.listV = v
   108  	w.modified = true
   109  }
   110  
   111  // Show displays the specified child widget within the Window.
   112  func (w *Window) Show(index int) {
   113  	w.Lock()
   114  	defer w.Unlock()
   115  
   116  	if index >= 0 && index < len(w.children) {
   117  		w.active = index
   118  		SetFocus(w.defaultFocus[index])
   119  	} else {
   120  		w.active = -1
   121  	}
   122  	w.modified = true
   123  }
   124  
   125  // Hide hides the currently visible child widget.
   126  func (w *Window) Hide() {
   127  	w.Lock()
   128  	defer w.Unlock()
   129  
   130  	w.active = -1
   131  	w.modified = true
   132  }
   133  
   134  // Children returns the children of the widget.
   135  func (w *Window) Children() []Widget {
   136  	w.Lock()
   137  	defer w.Unlock()
   138  
   139  	if w.active >= 0 && w.active < len(w.children) {
   140  		if w.listSize > 0 {
   141  			return []Widget{w.children[w.active], w.listWidget}
   142  		}
   143  		return []Widget{w.children[w.active]}
   144  	} else if w.listSize > 0 {
   145  		return []Widget{w.listWidget}
   146  	}
   147  	return nil
   148  }
   149  
   150  // Clear removes all children from the widget.
   151  func (w *Window) Clear() {
   152  	w.Lock()
   153  	defer w.Unlock()
   154  
   155  	w.children = w.children[:0]
   156  	w.labels = w.labels[:0]
   157  	w.active = -1
   158  	w.listModified = true
   159  	w.firstDraw = true
   160  }
   161  
   162  func (w *Window) selectItem(index int) (accept bool) {
   163  	if index >= 0 && index < len(w.children) {
   164  		w.active = index
   165  		w.modified = true
   166  		SetFocus(w.defaultFocus[index])
   167  	}
   168  	return true
   169  }
   170  
   171  // HandleKeyboard is called when a keyboard event occurs.
   172  func (w *Window) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
   173  	return true, nil
   174  }
   175  
   176  // HandleMouse is called when a mouse event occurs.
   177  func (w *Window) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
   178  	return true, nil
   179  }
   180  
   181  // Draw draws the widget on the screen.
   182  func (w *Window) Draw(screen *ebiten.Image) error {
   183  	if w.listModified {
   184  		w.list.SetItemHeight(int(float64(Scale(w.fontSize)) * 1.5))
   185  		w.list.Clear()
   186  		for i := range w.labels {
   187  			label := w.labels[i]
   188  			if label == "" {
   189  				label = fmt.Sprintf("#%d", i)
   190  			}
   191  			t := NewText(label)
   192  			t.SetFont(w.font, Scale(w.fontSize))
   193  			t.SetAutoResize(true)
   194  			t.SetVertical(AlignCenter)
   195  			w.list.AddChildAt(t, 0, i)
   196  			w.list.SetSelectedItem(0, w.active)
   197  		}
   198  		w.listModified = false
   199  	}
   200  	if w.modified {
   201  		if w.active >= 0 {
   202  			wr := w.rect
   203  			if w.listSize > 0 {
   204  				var lr image.Rectangle
   205  				switch w.listH {
   206  				case AlignStart:
   207  					lr = image.Rect(wr.Min.X, wr.Min.Y, wr.Min.X+w.listSize, wr.Max.Y)
   208  				case AlignEnd:
   209  					lr = image.Rect(wr.Max.X-w.listSize, wr.Min.Y, wr.Max.X, wr.Max.Y)
   210  				}
   211  				switch w.listV {
   212  				case AlignStart:
   213  					lr = image.Rect(wr.Min.X, wr.Min.Y, wr.Max.X, wr.Min.Y+w.listSize)
   214  				case AlignEnd:
   215  					lr = image.Rect(wr.Min.X, wr.Max.Y-w.listSize, wr.Max.X, wr.Max.Y)
   216  				}
   217  				dx, dy := lr.Dx(), lr.Dy()
   218  				if dx > 0 && dy > 0 && dx <= wr.Dx() && dy <= wr.Dy() {
   219  					switch w.listH {
   220  					case AlignStart:
   221  						wr.Min.X += w.listSize
   222  					case AlignEnd:
   223  						wr.Max.X -= w.listSize
   224  					}
   225  					switch w.listV {
   226  					case AlignStart:
   227  						wr.Min.Y += w.listSize
   228  					case AlignEnd:
   229  						wr.Max.Y -= w.listSize
   230  					}
   231  					w.list.SetRect(lr)
   232  				}
   233  			}
   234  			w.children[w.active].SetRect(wr)
   235  			if w.firstDraw {
   236  				SetFocus(w.children[w.active])
   237  				w.firstDraw = false
   238  			}
   239  		}
   240  		w.modified = false
   241  	}
   242  	return nil
   243  }
   244  
   245  // AddChild adds a child to the window.
   246  func (w *Window) AddChild(wgt ...Widget) {
   247  	w.Lock()
   248  	defer w.Unlock()
   249  
   250  	for _, widget := range wgt {
   251  		w.children = append(w.children, widget)
   252  		w.defaultFocus = append(w.defaultFocus, widget)
   253  		w.labels = append(w.labels, "")
   254  	}
   255  	w.modified = true
   256  	w.listModified = true
   257  }
   258  
   259  // AddChildWithLabel adds a child to the window with the specified default focus and list entry label.
   260  func (w *Window) AddChildWithLabel(wgt Widget, defaultFocus Widget, label string) int {
   261  	w.Lock()
   262  	defer w.Unlock()
   263  
   264  	w.children = append(w.children, wgt)
   265  	w.defaultFocus = append(w.defaultFocus, defaultFocus)
   266  	w.labels = append(w.labels, label)
   267  
   268  	w.modified = true
   269  	w.listModified = true
   270  	return len(w.children) - 1
   271  }
   272  

View as plain text