Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions demos/styles/dub.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"copyright": "Copyright 2025 Garrett D'Amore",
"description": "Styles Demo for Dcell",
"name": "styles",
"targetType": "executable",
"targetName": "styles",
"targetPath": "bin",
"mainSourceFile": "source/styles.d",
"dependencies": {
"dcell": { "path": "../.." }
}
}
179 changes: 179 additions & 0 deletions demos/styles/source/styles.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/**
* Styles world demo for Dcell.
*
* Copyright: Copyright 2025 Garrett D'Amore
* Authors: Garrett D'Amore
* License:
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or https://www.boost.org/LICENSE_1_0.txt)
* SPDX-License-Identifier: BSL-1.0
*/
module styles;

import std.stdio;
import std.string;

import dcell;

void centerStr(Screen s, int y, Style style, string str)
{
s.style = style;
s.position = Coord((s.size.x - cast(int)(str.length)) / 2, y);
s.write(str);
}

void displayStyles(Screen s)
{

s.style.attr = Attr.bold;
s.style.fg = Color.black;
s.style.bg = Color.white;

s.clear();

s.style.fg = Color.blue;
s.style.bg = Color.silver;

int row = 2;
s.position = Coord(2, row);
s.write("Press ESC to Exit");
row += 2;

s.style.fg = Color.black;
s.style.bg = Color.white;

s.position = Coord(2, row);
s.style.attr = Attr.none;
s.write("Note: Style support is dependent on your terminal.");
row += 2;

s.style.attr = Attr.none;
s.position = Coord(2, row++);
s.write("Plain");

s.style.attr = Attr.blink;
s.position = Coord(2, row++);
s.write("Blink");

s.style.attr = Attr.reverse;
s.position = Coord(2, row++);
s.write("Reverse");

s.style.attr = Attr.dim;
s.position = Coord(2, row++);
s.write("Dim");

s.style.attr = Attr.underline;
s.position = Coord(2, row++);
s.write("Underline");

s.style.attr = Attr.italic;
s.position = Coord(2, row++);
s.write("Italic");

s.style.attr = Attr.bold;
s.position = Coord(2, row++);
s.write("Bold");

s.style.attr = Attr.bold | Attr.italic;
s.position = Coord(2, row++);
s.write("Bold Italic");

s.style.attr = Attr.bold | Attr.italic | Attr.underline;
s.position = Coord(2, row++);
s.write("Bold Italic Underline");

s.style.attr = Attr.strikethrough;
s.position = Coord(2, row++);
s.write("Strikethrough");

s.style.attr = Attr.doubleUnderline;
s.position = Coord(2, row++);
s.write("Double Underline");

s.style.attr = Attr.curlyUnderline;
s.position = Coord(2, row++);
s.write("Curly Underline");

s.style.attr = Attr.dottedUnderline;
s.position = Coord(2, row++);
s.write("Dotted Underline");

s.style.attr = Attr.dashedUnderline;
s.position = Coord(2, row++);
s.write("Dashed Underline");

s.style.attr = Attr.underline;
s.style.ul = Color.blue;
s.position = Coord(2, row++);
s.write("Blue Underline");

s.style.attr = Attr.curlyUnderline;
s.style.ul = fromHex(0xc58af9);
s.position = Coord(2, row++);
s.write("Lavender Curly Underline");

s.style.attr = Attr.none;
s.style.ul = Color.invalid;
s.position = Coord(2, row++);
s.style.url = "https://github.com/gdamore/dcell";
s.write("Hyperlink");
s.style.url = "";

s.style.attr = Attr.none;
s.style.fg = Color.red;
s.position = Coord(2, row++);
s.write("Red Foreground");

s.style.attr = Attr.none;
s.style.bg = Color.red;
s.style.fg = Color.black;
s.position = Coord(2, row++);
s.write("Red Background");

s.show();
}

void handleEvent(Screen ts, Event ev)
{
import core.stdc.stdlib : exit;

switch (ev.type)
{
case EventType.key:
if (ev.key.key == Key.esc || ev.key.key == Key.f1)
{
ts.stop();
exit(0);
}
break;
case EventType.resize:
ts.resize();
displayStyles(ts);
ts.sync();
break;
default:
break;
}
}

void main()
{
import std.stdio;

auto ts = newScreen();
assert(ts !is null);
scope (exit)
{
ts.stop();
}

ts.start();

displayStyles(ts);
for (;;)
{
Event ev = ts.waitEvent();
handleEvent(ts, ev);
}
}
20 changes: 15 additions & 5 deletions source/dcell/attr.d
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,20 @@ enum Attr
bold = 1 << 0,
blink = 1 << 1,
reverse = 1 << 2, /// foreground and background colors reversed
underline = 1 << 3,
dim = 1 << 4,
italic = 1 << 5,
strikethrough = 1 << 6,
invalid = 1 << 7, // invalid attribute
dim = 1 << 3,
italic = 1 << 4,
strikethrough = 1 << 5,

/// Underlines are a bit field, because they can be styled. Use a ^= underlineMask; a |= plainUnderline.
/// If you only use simple underlines you can just set underline as a bool.
underline = 1 << 6,
plainUnderline = underline | 0 << 7,
doubleUnderline = underline | 1 << 7,
curlyUnderline = underline | 2 << 7, // underline styles take bits 7-9
dottedUnderline = underline | 3 << 7,
dashedUnderline = underline | 4 << 7,
underlineMask = underline | 7 << 7, // all bits set for underline

invalid = 1 << 15, // invalid attribute
init = invalid,
}
2 changes: 1 addition & 1 deletion source/dcell/screen.d
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ interface Screen
* The style property is used when writing content to the screen
* using the simpler write() API.
*/
@property Style style() const @safe;
@property ref Style style() @safe;
@property Style style(const(Style)) @safe;

/**
Expand Down
1 change: 1 addition & 0 deletions source/dcell/style.d
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct Style
{
Color fg; /// foreground color
Color bg; /// background color
Color ul; /// underline color (when underline is in use)
string url; /// clickable URL, or none if empty
Attr attr; /// text attributes
}
81 changes: 65 additions & 16 deletions source/dcell/ttyscreen.d
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ class TtyScreen : Screen
enum string enableDrag = "\x1b[?1002h";
enum string enableMotion = "\x1b[?1003h";
enum string mouseSgr = "\x1b[?1006h"; // SGR reporting (use with other enables)
enum string doubleUnder = "\x1b[4:2m";
enum string curlyUnder = "\x1b[4:3m";
enum string dottedUnder = "\x1b[4:4m";
enum string dashedUnder = "\x1b[4:5m";
enum string underColor = "\x1b[58:5:%dm";
enum string underRGB = "\x1b[58:2::%d:%d:%dm";
enum string underFg = "\x1b[59m";

// these can be overridden (e.g. disabled for legacy)
string enterURL = "\x1b]8;;%s\x1b\\";
Expand Down Expand Up @@ -122,13 +129,6 @@ class TtyScreen : Screen
// variables.)
int numColors = 256;

// doubleUnder = "\x1b[4:2m"
// curlyUnder = "\x1b[4:3m"
// dottedUnder = "\x1b[4:4m"
// dashedUnder = "\x1b[4:5m"
// underColor = "\x1b[58:5:%dm"
// underRGB = "\x1b[58:2::%d:%d:%dm"
// underFg = "\x1b[59m"
// requestWindowSize = "\x1b[18t" // For modern terminals
}

Expand Down Expand Up @@ -314,6 +314,9 @@ class TtyScreen : Screen

void clear()
{
// save the style currently in effect, so when
// we later send the clear, we can use it.
baseStyle = style;
fill(" ");
clear_ = true;
// because we are going to clear it in the next cycle,
Expand Down Expand Up @@ -502,7 +505,7 @@ class TtyScreen : Screen

// This is the default style we use when writing content using
// put and similar APIs.
@property Style style() const @safe
@property ref Style style() @safe
{
return cells.style;
}
Expand Down Expand Up @@ -552,6 +555,7 @@ private:
bool clear_; // if a screen clear is requested
Coord pos_; // location where we will update next
Style style_; // current style
Style baseStyle;
Coord cursorPos;
Cursor cursorShape;
MouseEnable mouseEn; // saved state for suspend/resume
Expand Down Expand Up @@ -589,6 +593,24 @@ private:
{
return;
}

if (style.ul.isValid && (style.attr & Attr.underlineMask))
{
if (style.ul == Color.reset)
{
puts(vt.underFg);
}
else if (style.ul.isRGB && vt.numColors > 256)
{
auto rgb = decompose(style.ul);
puts(format!(vt.underRGB)(rgb[0], rgb[1], rgb[2]));
}
else
{
auto ul = toPalette(style.ul, vt.numColors);
puts(format!(vt.underColor)(ul));
}
}
if (fg == Color.reset || bg == Color.reset)
{
puts(vt.resetFgBg);
Expand Down Expand Up @@ -641,25 +663,51 @@ private:
{
auto attr = style.attr;
if (attr & Attr.bold)
puts(Vt.bold);
if (attr & Attr.underline)
puts(Vt.underline);
puts(vt.bold);
if (attr & Attr.reverse)
puts(Vt.reverse);
puts(vt.reverse);
if (attr & Attr.blink)
puts(Vt.blink);
puts(vt.blink);
if (attr & Attr.dim)
puts(Vt.dim);
puts(vt.dim);
if (attr & Attr.italic)
puts(Vt.italic);
puts(vt.italic);
if (attr & Attr.strikethrough)
puts(Vt.strikeThrough);
puts(vt.strikeThrough);
switch (attr & Attr.underlineMask)
{
case Attr.plainUnderline:
puts(vt.underline);
break;
case attr.doubleUnderline:
puts(vt.underline);
puts(vt.doubleUnder);
break;
case Attr.curlyUnderline:
puts(vt.underline);
puts(vt.curlyUnder);
break;
case Attr.dottedUnderline:
puts(vt.underline);
puts(vt.dottedUnder);
break;
case Attr.dashedUnderline:
puts(vt.underline);
puts(vt.dashedUnder);
break;
default:
break;
}
}

void clearScreen()
{
if (clear_)
{
// We want to use the style that was in effect
// when the clear function was called.
Style savedStyle = style;
style = baseStyle;
clear_ = false;
puts(vt.sgr0);
puts(vt.exitURL);
Expand All @@ -668,6 +716,7 @@ private:
style_ = style;
puts(Vt.clear);
flush();
style = savedStyle;
}
}

Expand Down