-
Notifications
You must be signed in to change notification settings - Fork 1
/
detailview-render.c
170 lines (146 loc) · 5.44 KB
/
detailview-render.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "anigif-render.h"
#include "blast-render.h"
#include "detailview-render.h"
#include "detailview-thread.h"
#include "listview.h"
#include "listview-render.h"
#include "strutils.h"
#include "explode.h"
#define PADDING_TOP 1
#define PADDING_BOTTOM 1
void conch_detailview_render(detailview *v, WINDOW *window, winrect *rect) {
// Where to put the pad on screen
const int pad_screen_top = rect->top + PADDING_TOP;
const int pad_screen_bottom = rect->bottom - PADDING_BOTTOM;
const int pad_screen_height = rect->height - PADDING_TOP - PADDING_BOTTOM;
// Number of chars used to display line numbers
const int line_no_width = 4;
const bool dont_show_extended_markers = false;
drawlist *dl =
conch_blast_prepare(v->blastlist->current, rect->width - line_no_width,
dont_show_extended_markers);
int summary_height = dl->nlines;
int code_height = 0, code_width = 0;
if (v->blastlist->current->extended) {
code_height = count_lines_and_find_length_of_longest(
v->blastlist->current->extended, &code_width);
// Add an extra line in between the blast and the code block
summary_height++;
// Clamp the code_column_offset here. We might have resized since we last
// pressed a key, so this is the only place we can be sure to clamp
// correctly
if (v->code_column_offset + (rect->width - line_no_width) > code_width) {
v->code_column_offset = code_width - (rect->width - line_no_width);
}
if (v->code_column_offset < 0) {
v->code_column_offset = 0;
}
}
if (v->line_offset + pad_screen_height > summary_height + code_height) {
v->line_offset = summary_height + code_height - pad_screen_height;
}
if (v->line_offset < 0) {
v->line_offset = 0;
}
WINDOW *pad = newpad(summary_height + code_height, rect->width);
if (!pad) {
fatal_error("conch_detailview_render: Could not create vertical pad");
}
// Render the blast at 0,0 on the pad
conch_blast_render(pad, dl, dl->nlines, 0, line_no_width, dl->nlines, false);
conch_drawlist_free(dl);
// Flush renders to ncurses internal state.
wnoutrefresh(window);
if (v->blastlist->current->extended) {
for (unsigned int line = 1; line <= code_height; line++) {
mvwprintw(pad, line + summary_height - 1, 0, "%03d", line);
}
}
// Render the blast and also update the terminal with the combined state
//
// This pnoutrefresh splits the `if blast->extended` because we need to
// output the linenumbers (which pnoutrefreshdoes) before we render the code
// lines which need to overlay.
if (pnoutrefresh(pad, v->line_offset, 0, pad_screen_top, rect->left,
pad_screen_bottom, rect->right) == ERR) {
fatal_error("conch_detailview_render: Could not output pad to screen");
}
if (v->blastlist->current->extended) {
// waddstr will fail if we try to print outside of the pad. But it counts
// \n as a character on the previous line.
//
// TODO: Count the final \n in count_lines_and_find_length_of_longest then
// we can remove +1 from code_height
WINDOW *code_pad = newpad(code_height + 1, code_width + 1);
if (!code_pad) {
fatal_error(
"conch_detailview_render: Could not create code pad h: %d, w: %d",
code_height, code_width);
}
// There might be '\r' in the code snippet. Annoyingly when ncurses prints
// a '\r' it erases the line it just printed. So as a bit of a hack replace
// every '\r' with a ' '
char *string, *token;
string = token = strclone(v->blastlist->current->extended);
while ((token = strchr(token, '\r')) != NULL) {
*token = ' ';
}
int i = 0;
int err;
char const *cursl = string;
char const *cursr = string;
while (*cursr != '\0') {
if (*cursr == '\n') {
err = mvwaddnstr(code_pad, i++, 0, cursl, cursr - cursl + 1);
if (err == ERR) {
fatal_error("conch_detailview_render: mvwaddnstr of size %ld to "
"code_pad (width = %u) failed!",
cursr - cursl + 1, code_width + 1);
}
cursl = ++cursr;
continue;
}
cursr++;
}
free(string);
// Where the top of the code pad should be drawn to - if we have scrolled
// up this could be < 0
int code_pad_top = pad_screen_top + summary_height - v->line_offset,
code_scroll_top = 0;
// rect is unsigned, so we need to force it to signed so the comparison
// makes sense
if (code_pad_top < pad_screen_top) {
code_scroll_top = pad_screen_top - code_pad_top;
code_pad_top = pad_screen_top;
}
int left = rect->left + line_no_width;
if (pnoutrefresh(code_pad, code_scroll_top, v->code_column_offset,
code_pad_top, left, pad_screen_bottom,
rect->right) == ERR) {
fatal_error("Could not output codepad");
}
delwin(code_pad);
}
#ifndef NO_FETCH_THREAD
if (v->blastlist->current->attachment) {
if (v->fetch_thread != 0) {
conch_spinner_show();
conch_detailview_pollfetchthread(v);
}
}
#endif
delwin(pad);
// TODO: Render me properly into the pad so we can cope with an image and a
// code blast!
if (v->anigif) {
// Leave some padding between the image and the blast
summary_height++;
rect->height -= summary_height;
rect->top += summary_height;
anigif_render_frame(v->anigif, window, rect);
}
}