...

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  	"golang.org/x/image/font/sfnt"
     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         *sfnt.Font
    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  // SetFont sets the font and text size of the window titles. Scaling is not applied.
    59  func (w *Window) SetFont(fnt *sfnt.Font, size int) {
    60  	w.Lock()
    61  	defer w.Unlock()
    62  
    63  	w.font = fnt
    64  	w.fontSize = size
    65  	w.list.SetItemHeight(size)
    66  }
    67  
    68  // SetFrameSize sets the size of the frame around each window.
    69  func (w *Window) SetFrameSize(size int) {
    70  	w.Lock()
    71  	defer w.Unlock()
    72  
    73  	w.frameSize = size
    74  	w.modified = true
    75  }
    76  
    77  // SetListSize sets the width or height of the window tab list.
    78  func (w *Window) SetListSize(size int) {
    79  	w.Lock()
    80  	defer w.Unlock()
    81  
    82  	w.listSize = size
    83  	w.modified = true
    84  }
    85  
    86  // SetListHorizontal sets the horizontal alignment of the window tab list.
    87  func (w *Window) SetListHorizontal(h Alignment) {
    88  	w.Lock()
    89  	defer w.Unlock()
    90  
    91  	w.listH = h
    92  	w.modified = true
    93  }
    94  
    95  // SetListVertical sets the vertical alignment of the window tab list.
    96  func (w *Window) SetListVertical(v Alignment) {
    97  	w.Lock()
    98  	defer w.Unlock()
    99  
   100  	w.listV = v
   101  	w.modified = true
   102  }
   103  
   104  // Show displays the specified child widget within the Window.
   105  func (w *Window) Show(index int) {
   106  	w.Lock()
   107  	defer w.Unlock()
   108  
   109  	if index >= 0 && index < len(w.children) {
   110  		w.active = index
   111  		SetFocus(w.defaultFocus[index])
   112  	} else {
   113  		w.active = -1
   114  	}
   115  	w.modified = true
   116  }
   117  
   118  // Hide hides the currently visible child widget.
   119  func (w *Window) Hide() {
   120  	w.Lock()
   121  	defer w.Unlock()
   122  
   123  	w.active = -1
   124  	w.modified = true
   125  }
   126  
   127  // Children returns the children of the widget.
   128  func (w *Window) Children() []Widget {
   129  	w.Lock()
   130  	defer w.Unlock()
   131  
   132  	if w.active >= 0 && w.active < len(w.children) {
   133  		if w.listSize > 0 {
   134  			return []Widget{w.children[w.active], w.listWidget}
   135  		}
   136  		return []Widget{w.children[w.active]}
   137  	} else if w.listSize > 0 {
   138  		return []Widget{w.listWidget}
   139  	}
   140  	return nil
   141  }
   142  
   143  // Clear removes all children from the widget.
   144  func (w *Window) Clear() {
   145  	w.Lock()
   146  	defer w.Unlock()
   147  
   148  	w.children = w.children[:0]
   149  	w.labels = w.labels[:0]
   150  	w.active = -1
   151  	w.listModified = true
   152  	w.firstDraw = true
   153  }
   154  
   155  func (w *Window) selectItem(index int) (accept bool) {
   156  	if index >= 0 && index < len(w.children) {
   157  		w.active = index
   158  		w.modified = true
   159  		SetFocus(w.defaultFocus[index])
   160  	}
   161  	return true
   162  }
   163  
   164  // HandleKeyboard is called when a keyboard event occurs.
   165  func (w *Window) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
   166  	return true, nil
   167  }
   168  
   169  // HandleMouse is called when a mouse event occurs.
   170  func (w *Window) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
   171  	return true, nil
   172  }
   173  
   174  // Draw draws the widget on the screen.
   175  func (w *Window) Draw(screen *ebiten.Image) error {
   176  	if w.listModified {
   177  		w.list.SetItemHeight(int(float64(Scale(w.fontSize)) * 1.5))
   178  		w.list.Clear()
   179  		for i := range w.labels {
   180  			label := w.labels[i]
   181  			if label == "" {
   182  				label = fmt.Sprintf("#%d", i)
   183  			}
   184  			t := NewText(label)
   185  			t.SetFont(w.font, Scale(w.fontSize))
   186  			t.SetAutoResize(true)
   187  			t.SetVertical(AlignCenter)
   188  			w.list.AddChildAt(t, 0, i)
   189  			w.list.SetSelectedItem(0, w.active)
   190  		}
   191  		w.listModified = false
   192  	}
   193  	if w.modified {
   194  		if w.active >= 0 {
   195  			wr := w.rect
   196  			if w.listSize > 0 {
   197  				var lr image.Rectangle
   198  				switch w.listH {
   199  				case AlignStart:
   200  					lr = image.Rect(wr.Min.X, wr.Min.Y, wr.Min.X+w.listSize, wr.Max.Y)
   201  				case AlignEnd:
   202  					lr = image.Rect(wr.Max.X-w.listSize, wr.Min.Y, wr.Max.X, wr.Max.Y)
   203  				}
   204  				switch w.listV {
   205  				case AlignStart:
   206  					lr = image.Rect(wr.Min.X, wr.Min.Y, wr.Max.X, wr.Min.Y+w.listSize)
   207  				case AlignEnd:
   208  					lr = image.Rect(wr.Min.X, wr.Max.Y-w.listSize, wr.Max.X, wr.Max.Y)
   209  				}
   210  				dx, dy := lr.Dx(), lr.Dy()
   211  				if dx > 0 && dy > 0 && dx <= wr.Dx() && dy <= wr.Dy() {
   212  					switch w.listH {
   213  					case AlignStart:
   214  						wr.Min.X += w.listSize
   215  					case AlignEnd:
   216  						wr.Max.X -= w.listSize
   217  					}
   218  					switch w.listV {
   219  					case AlignStart:
   220  						wr.Min.Y += w.listSize
   221  					case AlignEnd:
   222  						wr.Max.Y -= w.listSize
   223  					}
   224  					w.list.SetRect(lr)
   225  				}
   226  			}
   227  			w.children[w.active].SetRect(wr)
   228  			if w.firstDraw {
   229  				SetFocus(w.children[w.active])
   230  				w.firstDraw = false
   231  			}
   232  		}
   233  		w.modified = false
   234  	}
   235  	return nil
   236  }
   237  
   238  // AddChild adds a child to the window.
   239  func (w *Window) AddChild(wgt ...Widget) {
   240  	w.Lock()
   241  	defer w.Unlock()
   242  
   243  	for _, widget := range wgt {
   244  		w.children = append(w.children, widget)
   245  		w.defaultFocus = append(w.defaultFocus, widget)
   246  		w.labels = append(w.labels, "")
   247  	}
   248  	w.modified = true
   249  	w.listModified = true
   250  }
   251  
   252  // AddChildWithLabel adds a child to the window with the specified default focus and list entry label.
   253  func (w *Window) AddChildWithLabel(wgt Widget, defaultFocus Widget, label string) int {
   254  	w.Lock()
   255  	defer w.Unlock()
   256  
   257  	w.children = append(w.children, wgt)
   258  	w.defaultFocus = append(w.defaultFocus, defaultFocus)
   259  	w.labels = append(w.labels, label)
   260  
   261  	w.modified = true
   262  	w.listModified = true
   263  	return len(w.children) - 1
   264  }
   265  

View as plain text