github.com/xyproto/orbiton/v2@v2.65.12-0.20240516144430-e10a419274ec/redraw.go (about)

     1  package main
     2  
     3  import (
     4  	"github.com/xyproto/vt100"
     5  )
     6  
     7  // FullResetRedraw will completely reset and redraw everything, including creating a brand new Canvas struct
     8  func (e *Editor) FullResetRedraw(c *vt100.Canvas, status *StatusBar, drawLines bool) {
     9  	savePos := e.pos
    10  
    11  	if status != nil {
    12  		status.ClearAll(c)
    13  		e.SetSearchTerm(c, status, "", false)
    14  	}
    15  
    16  	vt100.Close()
    17  	vt100.Reset()
    18  	vt100.Clear()
    19  	vt100.Init()
    20  
    21  	newC := vt100.NewCanvas()
    22  	newC.ShowCursor()
    23  	vt100.EchoOff()
    24  
    25  	w := int(newC.Width())
    26  
    27  	if (w < e.wrapWidth) || (e.wrapWidth < 80 && w >= 80) {
    28  		e.wrapWidth = w
    29  	}
    30  
    31  	if drawLines {
    32  		e.DrawLines(c, true, e.sshMode)
    33  	}
    34  
    35  	// Assign the new canvas to the current canvas
    36  	// All mutexes are unlocked at this point for the copying not to be worrysome.
    37  	*c = *newC
    38  
    39  	// TODO: Find out why the following lines are needed to properly handle the SIGWINCH resize signal
    40  
    41  	resizeMut.Lock()
    42  
    43  	newC = vt100.NewCanvas()
    44  	newC.ShowCursor()
    45  	vt100.EchoOff()
    46  	w = int(newC.Width())
    47  
    48  	resizeMut.Unlock()
    49  
    50  	if w < e.wrapWidth {
    51  		e.wrapWidth = w
    52  	} else if e.wrapWidth < 80 && w >= 80 {
    53  		e.wrapWidth = w
    54  	}
    55  
    56  	if drawLines {
    57  		e.DrawLines(c, true, e.sshMode)
    58  	}
    59  
    60  	if e.sshMode {
    61  		// TODO: Figure out why this helps doing a full redraw when o is used over ssh
    62  		// Go to the line we were at
    63  		e.ScrollUp(c, nil, e.pos.scrollSpeed)
    64  		e.DrawLines(c, true, true)
    65  		e.ScrollDown(c, nil, e.pos.scrollSpeed)
    66  		e.redraw = true
    67  		e.redrawCursor = true
    68  	} else {
    69  		e.redraw = false
    70  		e.redrawCursor = false
    71  	}
    72  
    73  	e.pos = savePos
    74  }
    75  
    76  // RedrawIfNeeded will redraw the text on the canvas if e.redraw is set
    77  func (e *Editor) RedrawIfNeeded(c *vt100.Canvas) {
    78  	if e.redraw {
    79  		respectOffset := true
    80  		redrawCanvas := e.sshMode
    81  		e.DrawLines(c, respectOffset, redrawCanvas)
    82  		e.redraw = false
    83  	}
    84  }
    85  
    86  // RepositionCursor will send the VT100 commands needed to position the cursor
    87  func (e *Editor) RepositionCursor(x, y int) {
    88  	// Redraw the cursor
    89  	vt100.SetXY(uint(x), uint(y))
    90  	e.previousX = x
    91  	e.previousY = y
    92  }
    93  
    94  // RepositionCursorIfNeeded will reposition the cursor using VT100 commands, if needed
    95  func (e *Editor) RepositionCursorIfNeeded() {
    96  	// Redraw the cursor, if needed
    97  	x := e.pos.ScreenX()
    98  	y := e.pos.ScreenY()
    99  	if e.redrawCursor || x != e.previousX || y != e.previousY {
   100  		e.RepositionCursor(x, y)
   101  		e.redrawCursor = false
   102  	}
   103  }
   104  
   105  // DrawLines will draw a screen full of lines on the given canvas
   106  func (e *Editor) DrawLines(c *vt100.Canvas, respectOffset, redrawCanvas bool) {
   107  	h := int(c.Height())
   108  	if respectOffset {
   109  		offsetY := e.pos.OffsetY()
   110  		e.WriteLines(c, LineIndex(offsetY), LineIndex(h+offsetY), 0, 0)
   111  	} else {
   112  		e.WriteLines(c, LineIndex(0), LineIndex(h), 0, 0)
   113  	}
   114  	if redrawCanvas {
   115  		c.Redraw()
   116  	} else {
   117  		c.Draw()
   118  	}
   119  }
   120  
   121  // InitialRedraw is called right before the main loop is started
   122  func (e *Editor) InitialRedraw(c *vt100.Canvas, status *StatusBar) {
   123  	// Check if an extra reset is needed
   124  	if e.sshMode {
   125  		drawLines := true
   126  		e.FullResetRedraw(c, status, drawLines)
   127  	} else {
   128  		// Draw the editor lines, respect the offset (true) and redraw (true)
   129  		e.RedrawIfNeeded(c)
   130  	}
   131  
   132  	// Display the status message
   133  	if e.nanoMode {
   134  		status.Show(c, e)
   135  	} else if e.statusMode {
   136  		status.ShowLineColWordCount(c, e, e.filename)
   137  	} else if status.IsError() {
   138  		status.Show(c, e)
   139  	}
   140  
   141  	if status.messageAfterRedraw != "" {
   142  		status.Clear(c)
   143  		status.SetMessage(status.messageAfterRedraw)
   144  		status.Show(c, e)
   145  		status.messageAfterRedraw = ""
   146  	}
   147  
   148  	e.RepositionCursorIfNeeded()
   149  }
   150  
   151  // RedrawAtEndOfKeyLoop is called after each main loop
   152  func (e *Editor) RedrawAtEndOfKeyLoop(c *vt100.Canvas, status *StatusBar) {
   153  	redrawCanvas := !e.debugMode
   154  
   155  	// Redraw, if needed
   156  	if e.redraw {
   157  		// Draw the editor lines on the canvas, respecting the offset
   158  		e.DrawLines(c, true, redrawCanvas)
   159  		e.redraw = false
   160  
   161  		if e.drawProgress {
   162  			e.DrawProgress(c)
   163  			e.drawProgress = false
   164  		}
   165  	} else if e.Changed() {
   166  		c.Draw()
   167  
   168  		if e.drawProgress {
   169  			e.DrawProgress(c)
   170  			e.drawProgress = false
   171  		}
   172  	}
   173  
   174  	// Drawing status messages should come after redrawing, but before cursor positioning
   175  	if e.nanoMode {
   176  		status.Show(c, e)
   177  	} else if e.statusMode {
   178  		status.ShowLineColWordCount(c, e, e.filename)
   179  	} else if status.IsError() {
   180  		// Show the status message, if *statusMessage is not set
   181  		if status.messageAfterRedraw == "" {
   182  			status.Show(c, e)
   183  		}
   184  	}
   185  
   186  	if status.messageAfterRedraw != "" {
   187  		status.Clear(c)
   188  		status.SetMessage(status.messageAfterRedraw)
   189  		status.messageAfterRedraw = ""
   190  		status.Show(c, e)
   191  	}
   192  
   193  	e.RepositionCursorIfNeeded()
   194  }