Skip to content

Commit 217e567

Browse files
author
Timothy Johnson
committed
Double-wide and double-high line support.
1 parent 8b11a99 commit 217e567

File tree

4 files changed

+180
-6
lines changed

4 files changed

+180
-6
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ vala_precompile(VALA_C
6161
src/TerminalOutput.vala
6262
src/CharacterAttributes.vala
6363
src/TerminalView.vala
64+
src/TextView.vala
6465
src/TerminalWidget.vala
6566
src/NestingContainer.vala
6667
src/Autocompletion.vala

src/TerminalOutput.vala

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,36 @@ public class TerminalOutput : Gtk.TextBuffer {
170170
line_updated(cursor_position.line);
171171
break;
172172

173+
case TerminalStream.StreamElement.ControlSequenceType.DEC_DOUBLE_WIDTH_LINE:
174+
Gtk.TextIter start, end;
175+
get_iter_at_line(out start, cursor_position.line);
176+
get_iter_at_line(out end, cursor_position.line);
177+
end.forward_to_line_end();
178+
179+
// Add tag to entire line. Text drawn in TextView.draw_layer
180+
apply_tag(tag_table.lookup("double-wide") ?? create_tag("double-wide", "invisible", true), start, end);
181+
break;
182+
183+
case TerminalStream.StreamElement.ControlSequenceType.DEC_DOUBLE_HEIGHT_LINE_TOP_HALF:
184+
Gtk.TextIter start, end;
185+
get_iter_at_line(out start, cursor_position.line);
186+
get_iter_at_line(out end, cursor_position.line);
187+
end.forward_to_line_end();
188+
189+
// Add tag to entire line. Text drawn in TextView.draw_layer
190+
apply_tag(tag_table.lookup("double-top") ?? create_tag("double-top", "invisible", true), start, end);
191+
break;
192+
193+
case TerminalStream.StreamElement.ControlSequenceType.DEC_DOUBLE_HEIGHT_LINE_BOTTOM_HALF:
194+
Gtk.TextIter start, end;
195+
get_iter_at_line(out start, cursor_position.line);
196+
get_iter_at_line(out end, cursor_position.line);
197+
end.forward_to_line_end();
198+
199+
// Add tag to entire line. Text drawn in TextView.draw_layer
200+
apply_tag(tag_table.lookup("double-bottom") ?? create_tag("double-bottom", "invisible", true), start, end);
201+
break;
202+
173203
case TerminalStream.StreamElement.ControlSequenceType.BELL:
174204
// TODO: Beep on the terminal window rather than the default display
175205
Gdk.beep();
@@ -912,6 +942,25 @@ public class TerminalOutput : Gtk.TextBuffer {
912942
foreach (var tag in tags)
913943
apply_tag(tag, start, iter);
914944

945+
// If this is a double-wide or double-high line expand tag to the new line end
946+
if (!start.ends_line())
947+
{
948+
var end = start;
949+
end.forward_to_line_end();
950+
951+
var tag = tag_table.lookup("double-wide");
952+
if (tag != null && start.ends_tag(tag))
953+
apply_tag(tag, start, end);
954+
955+
tag = tag_table.lookup("double-top");
956+
if (tag != null && start.ends_tag(tag))
957+
apply_tag(tag, start, end);
958+
959+
tag = tag_table.lookup("double-bottom");
960+
if (tag != null && start.ends_tag(tag))
961+
apply_tag(tag, start, end);
962+
}
963+
915964
start = iter;
916965

917966
// Printed text should overwrite previous content on the line

src/TerminalView.vala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class TerminalView : Fixed {
3939

4040
var box = new Box (Orientation.VERTICAL, 5);
4141
put (box, 0, 0);
42-
42+
4343
size_allocate.connect((alloc) => {
4444
var child = Gtk.Allocation ();
4545
child.x = 0;
@@ -103,9 +103,6 @@ public class TerminalOutputView : ScrolledWindow {
103103
this.terminal = terminal;
104104

105105
view = new TextView.with_buffer (terminal.terminal_output);
106-
view.editable = false;
107-
view.cursor_visible = false;
108-
view.wrap_mode = WrapMode.CHAR;
109106
view.motion_notify_event.connect(on_motion_notify_event);
110107
view.button_press_event.connect(on_button_press_event);
111108
view.has_tooltip = true;
@@ -377,7 +374,7 @@ public class TerminalOutputView : ScrolledWindow {
377374
}
378375

379376
public void scroll_to_position(TerminalOutput.CursorPosition position = {-1, -1}) {
380-
if (position.line == -1 && position.column == -1)
377+
if (position.line == -1 && position.column == -1)
381378
// Default: Scroll to end
382379
vadjustment.value = vadjustment.upper;
383380
else {
@@ -431,4 +428,4 @@ public class TerminalOutputView : ScrolledWindow {
431428
// TODO: Use Utilities.schedule_execution here?
432429
terminal.update_size();
433430
}
434-
}
431+
}

src/TextView.vala

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright © 2013–2014 Philipp Emanuel Weidmann <[email protected]>
3+
* Copyright © 2015-2016 RedHatter <[email protected]>
4+
*
5+
* Nemo vir est qui mundum non reddat meliorem.
6+
*
7+
*
8+
* This file is part of Final Term.
9+
*
10+
* Final Term is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License as published by
12+
* the Free Software Foundation, either version 3 of the License, or
13+
* (at your option) any later version.
14+
*
15+
* Final Term is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License
21+
* along with Final Term. If not, see <http://www.gnu.org/licenses/>.
22+
*/
23+
24+
using Gtk;
25+
using Pango;
26+
27+
/**
28+
* Custom TextView to draw double-wide and double-high text.
29+
*/
30+
public class TextView : Gtk.TextView {
31+
public TextView.with_buffer (TextBuffer buffer) {
32+
set_buffer(buffer);
33+
editable = false;
34+
cursor_visible = false;
35+
wrap_mode = Gtk.WrapMode.CHAR;
36+
}
37+
38+
public override void draw_layer (TextViewLayer layer, Cairo.Context cr) {
39+
// Draw after text has been rendered
40+
if (layer != TextViewLayer.BELOW)
41+
return;
42+
43+
//TODO: Cache layout
44+
var line = create_pango_layout(null);
45+
TextIter iter;
46+
47+
// For each of the three types obtain the text using
48+
// forward_to_tag_toggle, apply line styles, set clip, and draw with
49+
// Cairo transforms
50+
51+
// Double-wide: scale x by a factor of 2
52+
buffer.get_iter_at_line(out iter, 0);
53+
var tag = buffer.tag_table.lookup("double-wide");
54+
if (tag != null) {
55+
while (next_segment(cr, tag, ref iter, line)) {
56+
cr.scale(2.0, 1.0);
57+
Pango.cairo_show_layout(cr, line);
58+
cr.scale(0.5, 1.0);
59+
}
60+
}
61+
62+
// Double-high top half: scale both x and y by a factor of 2
63+
buffer.get_iter_at_line(out iter, 0);
64+
tag = buffer.tag_table.lookup("double-top");
65+
if (tag != null) {
66+
while (next_segment(cr, tag, ref iter, line)) {
67+
cr.scale(2.0, 2.0);
68+
Pango.cairo_show_layout(cr, line);
69+
cr.scale(0.5, 0.5);
70+
}
71+
}
72+
73+
// Double-high bottom half: scale both x and y by a factor of 2 and
74+
// shift y up one line
75+
buffer.get_iter_at_line(out iter, 0);
76+
tag = buffer.tag_table.lookup("double-bottom");
77+
if (tag != null) {
78+
while (next_segment(cr, tag, ref iter, line)) {
79+
int line_height;
80+
get_line_yrange (iter, null, out line_height);
81+
cr.rel_move_to(0, -line_height);
82+
cr.scale(2.0, 2.0);
83+
Pango.cairo_show_layout(cr, line);
84+
cr.scale(0.5, 0.5);
85+
}
86+
}
87+
}
88+
89+
private bool next_segment (Cairo.Context cr, TextTag tag, ref TextIter iter, Pango.Layout line) {
90+
if (!iter.forward_to_tag_toggle(tag))
91+
return false; // No more segments
92+
93+
var start = iter;
94+
iter.forward_to_tag_toggle(tag);
95+
96+
// Extract text
97+
var text = buffer.get_text(start, iter, true);
98+
line.set_text(text, -1);
99+
100+
// TODO: Set all attribues from tags
101+
102+
// Set color attribute
103+
var color = get_default_attributes().appearance.fg_color;
104+
var attr = Pango.attr_foreground_new(color.red, color.green, color.blue);
105+
attr.start_index = 0;
106+
attr.end_index = text.length;
107+
var attr_list = new AttrList();
108+
attr_list.change((owned) attr);
109+
line.set_attributes(attr_list);
110+
111+
// Get position shifted by scroll
112+
Gdk.Rectangle pos_rect;
113+
get_cursor_locations(iter, out pos_rect, null);
114+
pos_rect.y -= (int) get_vadjustment().value;
115+
pos_rect.x -= (int) get_hadjustment().value;
116+
117+
// clip and move Cairo
118+
int height;
119+
line.get_pixel_size(null, out height);
120+
cr.reset_clip();
121+
cr.rectangle(pos_rect.x, pos_rect.y, get_allocated_width(), height);
122+
cr.clip();
123+
cr.move_to(pos_rect.x, pos_rect.y);
124+
125+
return true;
126+
}
127+
}

0 commit comments

Comments
 (0)