Skip to content

Commit

Permalink
Merge pull request #394 from sedwards2009/tips
Browse files Browse the repository at this point in the history
Tips & Colorizer extensions
  • Loading branch information
sedwards2009 authored Dec 9, 2022
2 parents 3683ff6 + d37d923 commit 453e69c
Show file tree
Hide file tree
Showing 53 changed files with 2,192 additions and 118 deletions.
3 changes: 3 additions & 0 deletions extensions/Colorizer/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: "extraterm"
};
3 changes: 3 additions & 0 deletions extensions/Colorizer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Colorizer Extension
===================
Detect and color keywords in the terminal output.
40 changes: 40 additions & 0 deletions extensions/Colorizer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "colorizer",
"displayName": "Colorizer",
"description": "Detect and color keywords in terminal output",
"author": "Simon Edwards",
"license": "MIT",
"version": "1.0.0",
"type": "module",
"exports": "./dist/ColorizerExtension.cjs",
"scripts": {
"build": "yarn run build-code && yarn run build-bundle && yarn run lint",
"build-code": "tsc",
"build-bundle": "esbuild build/ColorizerExtension.js --bundle --outfile=dist/ColorizerExtension.cjs --platform=node --format=cjs --external:@nodegui/nodegui \"--external:nodegui-plugin-*\"",
"clean": "shx rm -rf build dist",
"lint": "eslint \"src/**/*.ts\"",
"lint-strict": "eslint --max-warnings 1 \"src/**/*.ts\""
},
"devDependencies": {
"@extraterm/extraterm-extension-api": "0.15.0",
"esbuild": "^0.15.5",
"escape-string-regexp": "^5.0.0",
"eslint": "8.13.0",
"eslint-config-extraterm": "1.0.0",
"eslint-plugin-unicorn": "42.0.0",
"extraterm-unicode-utilities": "1.0.0",
"extraterm-uuid": "1.0.0",
"qt-construct": "0.1.0",
"shx": "^0.3.2",
"typescript": "4.7.4"
},
"contributes": {
"settingsTabs": [
{
"name": "colorizer-config",
"title": "Colorizer",
"icon": "fa-highlighter"
}
]
}
}
61 changes: 61 additions & 0 deletions extensions/Colorizer/src/ColorPatchButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2022 Simon Edwards <[email protected]>
*
* This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
*/
import { QColor, QPainter, QPushButton, WidgetEventTypes } from "@nodegui/nodegui";
import { PushButton } from "qt-construct";
import {
Event,
Logger,
} from "@extraterm/extraterm-extension-api";
import { EventEmitter } from "extraterm-event-emitter";


const BORDER_PX = 6; // TODO dpi


export class ColorPatchButton {
#log: Logger = null;
#widget: QPushButton = null;
#color: QColor = null;

#onClickedEventEmitter = new EventEmitter<void>();
onClicked: Event<void> = null;

constructor(checkable: boolean, log: Logger) {
this.#log = log;
this.onClicked = this.#onClickedEventEmitter.event;

this.#widget = PushButton({
cssClass: ["small"],
text: "",
checkable,
onClicked: () => {
this.#onClickedEventEmitter.fire();
}
});
this.#widget.addEventListener(WidgetEventTypes.Paint, (nativeEvent) => {
this.#handlePaint();
}, { afterDefault: true });
}

setColor(color: QColor): void {
this.#color = color;
this.#widget.update();
}

#handlePaint(): void {
const painter = new QPainter(this.#widget);
const patchColor = this.#color;
if (patchColor != null) {
const geo = this.#widget.geometry();
painter.fillRect(BORDER_PX, BORDER_PX, geo.width() - 2*BORDER_PX, geo.height() - 2*BORDER_PX, patchColor);
}
painter.end();
}

getWidget(): QPushButton {
return this.#widget;
}
}
98 changes: 98 additions & 0 deletions extensions/Colorizer/src/ColorPatchPopup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2022 Simon Edwards <[email protected]>
*
* This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
*/
import {
Event,
Logger,
TerminalSettings
} from "@extraterm/extraterm-extension-api";
import { BoxLayout, GridLayout, PushButton, Widget } from "qt-construct";
import { EventEmitter } from "extraterm-event-emitter";
import { Direction, QColor, QPushButton, QSizePolicyPolicy, QWidget, WidgetAttribute, WindowType } from "@nodegui/nodegui";
import { ColorPatchButton } from "./ColorPatchButton";

const NUMBER_OF_COLORS = 16;


export class ColorPatchPopup {

#onSelectedEventEmitter = new EventEmitter<number>();
onSelected: Event<number> = null;

#onClosedEventEmitter = new EventEmitter<void>();
onClosed: Event<void> = null;

#popup: QWidget = null;
#patches: ColorPatchButton[] = [];
#noneButton: QPushButton = null;

constructor(terminalSettings: TerminalSettings, log: Logger) {
this.onSelected = this.#onSelectedEventEmitter.event;
this.onClosed = this.#onClosedEventEmitter.event;

for (let i=0; i<NUMBER_OF_COLORS; i++) {
const colorIndex = i;
const patch = new ColorPatchButton(true, log);
patch.onClicked(() => {
this.#onSelectedEventEmitter.fire(colorIndex);
});
patch.setColor(new QColor(terminalSettings.currentTheme[i]));
this.#patches.push(patch);
}

this.#popup = Widget({
cssClass: ["window-background"],
windowFlag: WindowType.Popup,
contentsMargins: 0,
attribute: [
WidgetAttribute.WA_WindowPropagation,
WidgetAttribute.WA_X11NetWmWindowTypePopupMenu,
WidgetAttribute.WA_TranslucentBackground
],
sizePolicy: {
vertical: QSizePolicyPolicy.Minimum,
horizontal: QSizePolicyPolicy.Minimum,
},
onClose: () => {
this.#onClosedEventEmitter.fire();
},

layout: BoxLayout({
direction: Direction.TopToBottom,
children: [
{
layout: GridLayout({
columns: 8,
spacing: 0,
contentsMargins: [0, 0, 0, 0],
children: this.#patches.map(p => p.getWidget())
}),
stretch: 0
},

this.#noneButton = PushButton({
text: "None",
cssClass: ["small"],
checkable: true,
onClicked: () => {
this.#onSelectedEventEmitter.fire(null);
}
})
]
}),
});
}

getWidget(): QWidget {
return this.#popup;
}

setSelectedIndex(index: number): void {
for (let i=0; i<NUMBER_OF_COLORS; i++) {
this.#patches[i].getWidget().setChecked(i === index);
}
this.#noneButton.setChecked(index === null);
}
}
106 changes: 106 additions & 0 deletions extensions/Colorizer/src/ColorPatchSelector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright 2022 Simon Edwards <[email protected]>
*
* This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
*/
import {
Event,
Logger,
TerminalTheme,
} from "@extraterm/extraterm-extension-api";
import { Direction, QColor, QPoint, QSizePolicyPolicy, QWidget } from "@nodegui/nodegui";
import { EventEmitter } from "extraterm-event-emitter";
import { BoxLayout, Frame, Label, Widget } from "qt-construct";
import { ColorPatchButton } from "./ColorPatchButton";
import { ColorPatchPopup } from "./ColorPatchPopup";


export class ColorPatchSelector {

#onChangedEventEmitter = new EventEmitter<number>();
onChanged: Event<number> = null;

#terminalTheme: TerminalTheme = null;

#colorPatchButton: ColorPatchButton = null;
#colorPatchPopup: ColorPatchPopup = null;
#selectedIndex: number | null = null;
#topWidget: QWidget = null;

constructor(terminalTheme: TerminalTheme, colorPatchPopup: ColorPatchPopup, log: Logger) {
this.onChanged = this.#onChangedEventEmitter.event;
this.#colorPatchPopup = colorPatchPopup;

this.#colorPatchButton = new ColorPatchButton(false, log);
this.#colorPatchButton.onClicked(() => {
this.#handleOnClicked();
});

this.#topWidget = Frame({
cssClass: ["table-item"],
sizePolicy: {
vertical: QSizePolicyPolicy.Minimum,
horizontal: QSizePolicyPolicy.MinimumExpanding,
},
layout: BoxLayout({
direction: Direction.LeftToRight,
contentsMargins: 0,
spacing: 0,
children: [
{
widget: this.#colorPatchButton.getWidget(),
stretch: 0
},
{
widget: Widget({
sizePolicy: {
vertical: QSizePolicyPolicy.Minimum,
horizontal: QSizePolicyPolicy.MinimumExpanding,
}
}),
stretch: 1
}
]
})
});
this.#terminalTheme = terminalTheme;

this.setColorIndex(this.#selectedIndex);
}

setColorIndex(index: number): void {
const color = index == null ? null : new QColor(this.#terminalTheme[index]);
this.#colorPatchButton.setColor(color);
this.#selectedIndex = index;
}

getWidget(): QWidget {
return this.#topWidget;
}

#handleOnClicked(): void {
const widget = this.#colorPatchButton.getWidget();
const rect = widget.geometry();
const bottomLeft = widget.mapToGlobal(new QPoint(0, rect.height()));
const colorPatchPopupWidget = this.#colorPatchPopup.getWidget();
this.#colorPatchPopup.setSelectedIndex(this.#selectedIndex);

const dispose = () => {
onSelectedDisposable.dispose();
onCloseDisposable.dispose();
};

const onSelectedDisposable = this.#colorPatchPopup.onSelected((index: number) => {
dispose();
colorPatchPopupWidget.hide();
this.setColorIndex(index);
this.#onChangedEventEmitter.fire(index);
});
const onCloseDisposable = this.#colorPatchPopup.onClosed(dispose);

const hint = colorPatchPopupWidget.sizeHint();
colorPatchPopupWidget.setGeometry(bottomLeft.x(), bottomLeft.y(), hint.width(), hint.height());
colorPatchPopupWidget.raise();
colorPatchPopupWidget.show();
}
}
Loading

0 comments on commit 453e69c

Please sign in to comment.