diff options
| -rw-r--r-- | xA/xA.go | 181 | 
1 files changed, 175 insertions, 6 deletions
| @@ -118,9 +118,10 @@ type server struct {  type bufferLineItem struct {  	format fyne.TextStyle  	// For RichTextStyle.ColorName. -	// XXX: Fyne's RichText doesn't support background colours.  	color fyne.ThemeColorName -	text  string +	// XXX: Fyne's RichText doesn't support background colours. +	background fyne.ThemeColorName +	text       string  }  type bufferLine struct { @@ -188,6 +189,96 @@ var (  // ----------------------------------------------------------------------------- +func defaultBufferLineItem() bufferLineItem { return bufferLineItem{} } + +func convertItemFormatting( +	item RelayItemData, cf *bufferLineItem, inverse *bool) { +	switch data := item.Variant.(type) { +	case *RelayItemDataReset: +		*cf = defaultBufferLineItem() +	case *RelayItemDataFlipBold: +		cf.format.Bold = !cf.format.Bold +	case *RelayItemDataFlipItalic: +		cf.format.Italic = !cf.format.Italic +	case *RelayItemDataFlipUnderline: +		cf.format.Underline = !cf.format.Underline +	case *RelayItemDataFlipCrossedOut: +		// ¯\_(ツ)_/¯ +	case *RelayItemDataFlipInverse: +		*inverse = !*inverse +	case *RelayItemDataFlipMonospace: +		cf.format.Monospace = !cf.format.Monospace +	case *RelayItemDataFgColor: +		if data.Color < 0 { +			cf.color = "" +		} else { +			cf.color = ircColorName(int(data.Color)) +		} +	case *RelayItemDataBgColor: +		if data.Color < 0 { +			cf.background = "" +		} else { +			cf.background = ircColorName(int(data.Color)) +		} +	} +} + +func convertItems(items []RelayItemData) []bufferLineItem { +	result := []bufferLineItem{} +	cf, inverse := defaultBufferLineItem(), false +	for _, it := range items { +		text, ok := it.Variant.(*RelayItemDataText) +		if !ok { +			convertItemFormatting(it, &cf, &inverse) +			continue +		} + +		item := cf +		item.text = text.Text +		if inverse { +			item.color, item.background = item.background, item.color +		} +		result = append(result, item) +	} +	return result +} + +// ----------------------------------------------------------------------------- + +func bufferPrintLine(lines []bufferLine, index int) { +	// TODO(p): Date change. +	line := &lines[index] + +	// TODO(p): Timestamp. +	line.when.Format("\n15:04:05") + +	// TODO(p): Rendition. +	prefix := "" + +	if line.leaked { +		// TODO(p): Similar as below, but everything greyed out. +		if prefix != "" { +		} +		for _, item := range line.items { +			_ = item +		} +	} else { +		// TODO(p): Render text. +		if prefix != "" { +		} +		for _, item := range line.items { +			_ = item +		} +	} +} + +func bufferPrintSeparator() { +	// TODO(p) +	wRichText.Segments = append(wRichText.Segments, +		&widget.TextSegment{Style: widget.RichTextStyleParagraph}, +		&widget.SeparatorSegment{}) +} +  func refreshBuffer(b *buffer) {  	// TODO(p): See xW, rewrite the whole buffer view.  } @@ -293,6 +384,81 @@ func relayWriteMessage(conn net.Conn, data RelayCommandData) bool {  	return true  } +func convertBufferLine(m *RelayEventDataBufferLine) bufferLine { +	return bufferLine{ +		items:         convertItems(m.Items), +		isUnimportant: m.IsUnimportant, +		isHighlight:   m.IsHighlight, +		rendition:     m.Rendition, +		when:          time.UnixMilli(int64(m.When)), +	} +} + +func relayProcessBufferLine(b *buffer, m *RelayEventDataBufferLine) { +	line := convertBufferLine(m) + +	// Initial sync: skip all other processing, let highlights be. +	bc := bufferByName(bufferCurrent) +	if bc == nil { +		b.lines = append(b.lines, line) +		return +	} + +	// Retained mode is complicated. +	display := (!m.IsUnimportant || !bc.hideUnimportant) && +		(b.bufferName == bufferCurrent || m.LeakToActive) +	toBottom := display            // && bufferAtBottom() +	visible := display && toBottom // && ... +	separate := display && +		!visible && bc.newMessages == 0 && bc.newUnimportantMessages == 0 + +	b.lines = append(b.lines, line) +	if !(visible || m.LeakToActive) || +		b.newMessages != 0 || b.newUnimportantMessages != 0 { +		if line.isUnimportant || m.LeakToActive { +			b.newUnimportantMessages++ +		} else { +			b.newMessages++ +		} +	} + +	if m.LeakToActive { +		leakedLine := line +		leakedLine.leaked = true +		bc.lines = append(bc.lines, leakedLine) + +		if !visible || bc.newMessages != 0 || bc.newUnimportantMessages != 0 { +			if line.isUnimportant { +				bc.newUnimportantMessages++ +			} else { +				bc.newMessages++ +			} +		} +	} + +	if separate { +		// TODO(p) +	} +	if display { +		bufferPrintLine(bc.lines, len(bc.lines)-1) +	} +	if toBottom { +		// TODO(p) +	} + +	if line.isHighlight || (!visible && !line.isUnimportant && +		b.kind == RelayBufferKindPrivateMessage) { +		// TODO(p): beep(), probably using https://github.com/ebitengine/oto + +		if !visible { +			b.highlighted = true +			refreshIcon() +		} +	} + +	refreshBufferList() +} +  func relayProcessCallbacks(  	commandSeq uint32, err string, response *RelayResponseData) {  	if handler, ok := commandCallbacks[commandSeq]; !ok { @@ -338,7 +504,12 @@ func relayProcessMessage(m *RelayEventMessage) {  		}  	case *RelayEventDataBufferLine: -		// TODO(p): Process all remaining message kinds. +		b := bufferByName(data.BufferName) +		if b == nil { +			return +		} + +		relayProcessBufferLine(b, data)  	case *RelayEventDataBufferUpdate:  		b := bufferByName(data.BufferName)  		if b == nil { @@ -357,13 +528,11 @@ func relayProcessMessage(m *RelayEventMessage) {  		case *RelayBufferContextChannel:  			b.serverName = context.ServerName  			b.modes = context.Modes -			// TODO(p): Convert the items. -			b.topic = nil +			b.topic = convertItems(context.Topic)  		case *RelayBufferContextPrivateMessage:  			b.serverName = context.ServerName  		} -		// TODO: Port over the rest as well.  		if b.bufferName == bufferCurrent {  			refreshTopic(b.topic)  			refreshStatus() | 
