Skip to content

Commit

Permalink
Add text highlighting support in speech bubbles
Browse files Browse the repository at this point in the history
  • Loading branch information
AntumDeluge committed Mar 15, 2024
1 parent 1551389 commit 89eec90
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 8 deletions.
1 change: 1 addition & 0 deletions doc/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Changelog
- optional click/touch indicator
- fixed difficult to move small floating windows
- supports chat commands tab completion
- supports text highlighting in speech bubbles

*desktop client (non-Java)*
- experimental desktop interface for the web client using Neutralinojs
Expand Down
32 changes: 24 additions & 8 deletions srcjs/stendhal/sprite/SpeechBubble.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
* (C) Copyright 2003-2023 - Stendhal *
* (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
Expand All @@ -9,24 +9,34 @@
* *
***************************************************************************/

declare var stendhal: any;

import { TextBubble } from "./TextBubble";

import { RPEntity } from "../entity/RPEntity";
import { Speech } from "../util/Speech";

declare var stendhal: any;
import { Color } from "../util/Color";
import { Pair } from "../util/Pair";
import { Speech } from "../util/Speech";


export class SpeechBubble extends TextBubble {

private entity: RPEntity;
private offsetY: number;

/** Formatted sections. */
private parts: Pair<string, string>[];


constructor(text: string, entity: RPEntity) {
text = text.replace(/\\\\/g, "\\");
super((text.length > 30) ? (text.substring(0, 30) + "...") : text);
this.entity = entity;

this.parts = [];
this.segregate(this.parts);

this.offsetY = 0;
// find free text bubble position
const x = this.getX(), y = this.getY();
Expand All @@ -44,20 +54,26 @@ export class SpeechBubble extends TextBubble {
override draw(ctx: CanvasRenderingContext2D): boolean {
ctx.lineWidth = 2;
ctx.font = "14px Arial";
ctx.fillStyle = '#ffffff';
ctx.strokeStyle = "#000000";
ctx.fillStyle = Color.WHITE;
ctx.strokeStyle = Color.BLACK;

if (this.width < 0 || this.height < 0) {
// get width of text
this.width = ctx.measureText(this.text).width + 8;
this.height = 20;
}

const x = this.getX(), y = this.getY();
let x = this.getX(), y = this.getY();
Speech.drawBubbleRounded(ctx, x, y, this.width, this.height);

ctx.fillStyle = "#000000";
ctx.fillText(this.text, x + 4, y + TextBubble.adjustY);
x += 4;
ctx.save();
for (const p of this.parts) {
ctx.fillStyle = p.first;
ctx.fillText(p.second, x, y + TextBubble.adjustY);
x += ctx.measureText(p.second).width;
}
ctx.restore();

return this.expired();
}
Expand Down
52 changes: 52 additions & 0 deletions srcjs/stendhal/sprite/TextBubble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

declare var stendhal: any;

import { Color } from "../util/Color";
import { Pair } from "../util/Pair";


export abstract class TextBubble {

Expand Down Expand Up @@ -178,4 +181,53 @@ export abstract class TextBubble {
expired(): boolean {
return Date.now() >= this.timeStamp + this.duration;
}

/**
* Identifies indexes for formatting & removes symbols from text.
*
* @param parts {util.Pair.Pair[]}
* Array to be populated.
* @param defaultColor {string}
* Unformatted text color (default: `util.Color.Color.CHAT_NORMAL`).
*/
protected segregate(parts: Pair<string, string>[], defaultColor=Color.CHAT_NORMAL) {
let fillStyle = defaultColor;
let inHighlight = false, inHighlightQuote = false;
let idxStart = 0, idxEnd = 0;
for (idxEnd; idxEnd < this.text.length; idxEnd++) {
if (inHighlightQuote && this.text[idxEnd] === "'") {
inHighlightQuote = false;
inHighlight = false;
parts.push(new Pair(fillStyle, this.text.substring(idxStart, idxEnd)));
idxEnd++;
idxStart = idxEnd;
fillStyle = defaultColor;
} else if (!inHighlightQuote && inHighlight && this.text[idxEnd] === " ") {
inHighlight = false;
parts.push(new Pair(fillStyle, this.text.substring(idxStart, idxEnd)));
idxStart = idxEnd;
fillStyle = defaultColor;
} else if (this.text[idxEnd] === "#") {
inHighlight = true;
if (idxEnd > idxStart) {
parts.push(new Pair(fillStyle, this.text.substring(idxStart, idxEnd)));
}
fillStyle = Color.CHAT_HIGHLIGHT;
if (this.text[idxEnd+1] === "'") {
inHighlightQuote = true;
idxEnd++;
}
idxStart = idxEnd+1;
}
}
if (idxEnd > idxStart) {
// remainder
parts.push(new Pair(fillStyle, this.text.substring(idxStart, idxEnd)));
}
// remove symbols
this.text = "";
for (const p of parts) {
this.text += p.second;
}
}
}
1 change: 1 addition & 0 deletions srcjs/stendhal/util/Color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class Color {
public static readonly CHAT_ERROR = Color.RED;
public static readonly CHAT_GROUP = "rgb(00, 00, 160)"; // #0000A0 (dark blue)
public static readonly CHAT_HEAL = Color.GREEN;
public static readonly CHAT_HIGHLIGHT = Color.BLUE;
public static readonly CHAT_INFO = Color.ORANGE;
public static readonly CHAT_NEGATIVE = Color.RED;
public static readonly CHAT_NORMAL = Color.BLACK;
Expand Down

0 comments on commit 89eec90

Please sign in to comment.