...

Source file src/github.com/gdamore/tcell/v2/views/cellarea.go

Documentation: github.com/gdamore/tcell/v2/views

     1  // Copyright 2016 The Tcell Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use file except in compliance with the License.
     5  // You may obtain a copy of the license at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package views
    16  
    17  import (
    18  	"sync"
    19  
    20  	"github.com/gdamore/tcell/v2"
    21  )
    22  
    23  // CellModel models the content of a CellView.  The dimensions used within
    24  // a CellModel are always logical, and have origin 0, 0.
    25  type CellModel interface {
    26  	GetCell(x, y int) (rune, tcell.Style, []rune, int)
    27  	GetBounds() (int, int)
    28  	SetCursor(int, int)
    29  	GetCursor() (int, int, bool, bool)
    30  	MoveCursor(offx, offy int)
    31  }
    32  
    33  // CellView is a flexible view of a CellModel, offering both cursor
    34  // management and a panning.
    35  type CellView struct {
    36  	port     *ViewPort
    37  	view     View
    38  	content  Widget
    39  	contentV *ViewPort
    40  	style    tcell.Style
    41  	lines    []string
    42  	model    CellModel
    43  	once     sync.Once
    44  
    45  	WidgetWatchers
    46  }
    47  
    48  // Draw draws the content.
    49  func (a *CellView) Draw() {
    50  
    51  	port := a.port
    52  	model := a.model
    53  	port.Fill(' ', a.style)
    54  
    55  	if a.view == nil {
    56  		return
    57  	}
    58  	if model == nil {
    59  		return
    60  	}
    61  	vw, vh := a.view.Size()
    62  	for y := 0; y < vh; y++ {
    63  		for x := 0; x < vw; x++ {
    64  			a.view.SetContent(x, y, ' ', nil, a.style)
    65  		}
    66  	}
    67  
    68  	ex, ey := model.GetBounds()
    69  	vx, vy := port.Size()
    70  	if ex < vx {
    71  		ex = vx
    72  	}
    73  	if ey < vy {
    74  		ey = vy
    75  	}
    76  
    77  	cx, cy, en, sh := a.model.GetCursor()
    78  	for y := 0; y < ey; y++ {
    79  		for x := 0; x < ex; x++ {
    80  			ch, style, comb, wid := model.GetCell(x, y)
    81  			if ch == 0 {
    82  				ch = ' '
    83  				style = a.style
    84  			}
    85  			if en && x == cx && y == cy && sh {
    86  				style = style.Reverse(true)
    87  			}
    88  			port.SetContent(x, y, ch, comb, style)
    89  			x += wid - 1
    90  		}
    91  	}
    92  }
    93  
    94  func (a *CellView) keyUp() {
    95  	if _, _, en, _ := a.model.GetCursor(); !en {
    96  		a.port.ScrollUp(1)
    97  		return
    98  	}
    99  	a.model.MoveCursor(0, -1)
   100  	a.MakeCursorVisible()
   101  }
   102  
   103  func (a *CellView) keyDown() {
   104  	if _, _, en, _ := a.model.GetCursor(); !en {
   105  		a.port.ScrollDown(1)
   106  		return
   107  	}
   108  	a.model.MoveCursor(0, 1)
   109  	a.MakeCursorVisible()
   110  }
   111  
   112  func (a *CellView) keyLeft() {
   113  	if _, _, en, _ := a.model.GetCursor(); !en {
   114  		a.port.ScrollLeft(1)
   115  		return
   116  	}
   117  	a.model.MoveCursor(-1, 0)
   118  	a.MakeCursorVisible()
   119  }
   120  
   121  func (a *CellView) keyRight() {
   122  	if _, _, en, _ := a.model.GetCursor(); !en {
   123  		a.port.ScrollRight(1)
   124  		return
   125  	}
   126  	a.model.MoveCursor(+1, 0)
   127  	a.MakeCursorVisible()
   128  }
   129  
   130  func (a *CellView) keyPgUp() {
   131  	_, vy := a.port.Size()
   132  	if _, _, en, _ := a.model.GetCursor(); !en {
   133  		a.port.ScrollUp(vy)
   134  		return
   135  	}
   136  	a.model.MoveCursor(0, -vy)
   137  	a.MakeCursorVisible()
   138  }
   139  
   140  func (a *CellView) keyPgDn() {
   141  	_, vy := a.port.Size()
   142  	if _, _, en, _ := a.model.GetCursor(); !en {
   143  		a.port.ScrollDown(vy)
   144  		return
   145  	}
   146  	a.model.MoveCursor(0, +vy)
   147  	a.MakeCursorVisible()
   148  }
   149  
   150  func (a *CellView) keyHome() {
   151  	vx, vy := a.model.GetBounds()
   152  	if _, _, en, _ := a.model.GetCursor(); !en {
   153  		a.port.ScrollUp(vy)
   154  		a.port.ScrollLeft(vx)
   155  		return
   156  	}
   157  	a.model.SetCursor(0, 0)
   158  	a.MakeCursorVisible()
   159  }
   160  
   161  func (a *CellView) keyEnd() {
   162  	vx, vy := a.model.GetBounds()
   163  	if _, _, en, _ := a.model.GetCursor(); !en {
   164  		a.port.ScrollDown(vy)
   165  		a.port.ScrollRight(vx)
   166  		return
   167  	}
   168  	a.model.SetCursor(vx, vy)
   169  	a.MakeCursorVisible()
   170  }
   171  
   172  // MakeCursorVisible ensures that the cursor is visible, panning the ViewPort
   173  // as necessary, if the cursor is enabled.
   174  func (a *CellView) MakeCursorVisible() {
   175  	if a.model == nil {
   176  		return
   177  	}
   178  	x, y, enabled, _ := a.model.GetCursor()
   179  	if enabled {
   180  		a.MakeVisible(x, y)
   181  	}
   182  }
   183  
   184  // HandleEvent handles events.  In particular, it handles certain key events
   185  // to move the cursor or pan the view.
   186  func (a *CellView) HandleEvent(e tcell.Event) bool {
   187  	if a.model == nil {
   188  		return false
   189  	}
   190  	switch e := e.(type) {
   191  	case *tcell.EventKey:
   192  		switch e.Key() {
   193  		case tcell.KeyUp, tcell.KeyCtrlP:
   194  			a.keyUp()
   195  			return true
   196  		case tcell.KeyDown, tcell.KeyCtrlN:
   197  			a.keyDown()
   198  			return true
   199  		case tcell.KeyRight, tcell.KeyCtrlF:
   200  			a.keyRight()
   201  			return true
   202  		case tcell.KeyLeft, tcell.KeyCtrlB:
   203  			a.keyLeft()
   204  			return true
   205  		case tcell.KeyPgDn:
   206  			a.keyPgDn()
   207  			return true
   208  		case tcell.KeyPgUp:
   209  			a.keyPgUp()
   210  			return true
   211  		case tcell.KeyEnd:
   212  			a.keyEnd()
   213  			return true
   214  		case tcell.KeyHome:
   215  			a.keyHome()
   216  			return true
   217  		}
   218  	}
   219  	return false
   220  }
   221  
   222  // Size returns the content size, based on the model.
   223  func (a *CellView) Size() (int, int) {
   224  	// We always return a minimum of two rows, and two columns.
   225  	w, h := a.model.GetBounds()
   226  	// Clip to a 2x2 minimum square; we can scroll within that.
   227  	if w < 2 {
   228  		w = 2
   229  	}
   230  	if h < 2 {
   231  		h = 2
   232  	}
   233  	return w, h
   234  }
   235  
   236  // GetModel gets the model for this CellView
   237  func (a *CellView) GetModel() CellModel {
   238  	return a.model
   239  }
   240  
   241  // SetModel sets the model for this CellView.
   242  func (a *CellView) SetModel(model CellModel) {
   243  	w, h := model.GetBounds()
   244  	a.model = model
   245  	a.port.SetContentSize(w, h, true)
   246  	a.port.ValidateView()
   247  	a.PostEventWidgetContent(a)
   248  }
   249  
   250  // SetView sets the View context.
   251  func (a *CellView) SetView(view View) {
   252  	port := a.port
   253  	port.SetView(view)
   254  	a.view = view
   255  	if view == nil {
   256  		return
   257  	}
   258  	width, height := view.Size()
   259  	a.port.Resize(0, 0, width, height)
   260  	if a.model != nil {
   261  		w, h := a.model.GetBounds()
   262  		a.port.SetContentSize(w, h, true)
   263  	}
   264  	a.Resize()
   265  }
   266  
   267  // Resize is called when the View is resized.  It will ensure that the
   268  // cursor is visible, if present.
   269  func (a *CellView) Resize() {
   270  	// We might want to reflow text
   271  	width, height := a.view.Size()
   272  	a.port.Resize(0, 0, width, height)
   273  	a.port.ValidateView()
   274  	a.MakeCursorVisible()
   275  }
   276  
   277  // SetCursor sets the the cursor position.
   278  func (a *CellView) SetCursor(x, y int) {
   279  	a.model.SetCursor(x, y)
   280  }
   281  
   282  // SetCursorX sets the the cursor column.
   283  func (a *CellView) SetCursorX(x int) {
   284  	_, y, _, _ := a.model.GetCursor()
   285  	a.SetCursor(x, y)
   286  }
   287  
   288  // SetCursorY sets the the cursor row.
   289  func (a *CellView) SetCursorY(y int) {
   290  	x, _, _, _ := a.model.GetCursor()
   291  	a.SetCursor(x, y)
   292  }
   293  
   294  // MakeVisible makes the given coordinates visible, if they are not already.
   295  // It does this by moving the ViewPort for the CellView.
   296  func (a *CellView) MakeVisible(x, y int) {
   297  	a.port.MakeVisible(x, y)
   298  }
   299  
   300  // SetStyle sets the the default fill style.
   301  func (a *CellView) SetStyle(s tcell.Style) {
   302  	a.style = s
   303  }
   304  
   305  // Init initializes a new CellView for use.
   306  func (a *CellView) Init() {
   307  	a.once.Do(func() {
   308  		a.port = NewViewPort(nil, 0, 0, 0, 0)
   309  		a.style = tcell.StyleDefault
   310  	})
   311  }
   312  
   313  // NewCellView creates a CellView.
   314  func NewCellView() *CellView {
   315  	cv := &CellView{}
   316  	cv.Init()
   317  	return cv
   318  }
   319  

View as plain text