summaryrefslogtreecommitdiff
path: root/desktop/textarea.c
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/textarea.c')
-rw-r--r--desktop/textarea.c595
1 files changed, 411 insertions, 184 deletions
diff --git a/desktop/textarea.c b/desktop/textarea.c
index a048058f5..9dd3ace2d 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -82,6 +82,7 @@ struct textarea {
plot_font_style_t fstyle; /**< Text style, inc. textarea bg col */
plot_font_style_t sel_fstyle; /**< Selected text style */
+ int line_height; /**< Line height obtained from style */
struct textarea_utf8 text; /**< Textarea text content */
#define PASSWORD_REPLACEMENT "\xe2\x80\xa2"
@@ -102,10 +103,12 @@ struct textarea {
int h_extent; /**< Width of content in px */
int v_extent; /**< Height of content in px */
+
int line_count; /**< Count of lines */
+
#define LINE_CHUNK_SIZE 16
struct line_info *lines; /**< Line info array */
- int line_height; /**< Line height obtained from style */
+ unsigned int lines_alloc_size; /**< Number of LINE_CHUNK_SIZEs */
/** Callback function for messages to client */
textarea_client_callback callback;
@@ -260,67 +263,80 @@ static bool textarea_select_fragment(struct textarea * ta)
static bool textarea_scroll_visible(struct textarea *ta)
{
int x0, x1, y0, y1; /* area we want caret inside */
- int xc, yc; /* area centre */
int x, y; /* caret pos */
int xs = ta->scroll_x;
int ys = ta->scroll_y;
+ int vis;
+ int scrollbar_width;
bool scrolled = false;
if (ta->caret_pos.char_off == -1)
return false;
+ scrollbar_width = (ta->bar_y == NULL) ? 0 : SCROLLBAR_WIDTH;
x0 = ta->border_width + ta->pad_left;
x1 = ta->vis_width - (ta->border_width + ta->pad_right);
- y0 = 0;
- y1 = ta->vis_height - 2 * ta->border_width -
- ta->pad_top - ta->pad_bottom;
- xc = (x1 - x0) / 2 + x0;
- yc = (y1 - y0) / 2 + y0;
+ /* Adjust scroll pos for reduced extents */
+ vis = ta->vis_width - 2 * ta->border_width - scrollbar_width;
+ if (ta->h_extent - xs < vis)
+ xs -= vis - (ta->h_extent - xs);
+
+ /* Get caret pos on screen */
x = ta->caret_x - xs;
- y = ta->caret_y + ta->line_height / 2 - ys;
-
- /* horizontal scroll; centre caret */
- xs += x - xc;
-
- /* force back into range */
- if (xs < 0)
- xs = 0;
- else if (xs > ta->h_extent - (x1 - x0))
- xs = ta->h_extent - (x1 - x0);
-
- /* If scrolled, set new pos. */
- if (xs != ta->scroll_x && ta->bar_x != NULL) {
- scrollbar_set(ta->bar_x, xs, false);
- xs = scrollbar_get_offset(ta->bar_x);
- if (xs != ta->scroll_x) {
- ta->scroll_x = xs;
- scrolled = true;
- }
- } else if (ta->flags & TEXTAREA_MULTILINE && ta->bar_x == NULL &&
- ta->scroll_x != 0) {
+ /* scroll as required */
+ if (x < x0)
+ xs += (x - x0);
+ else if (x > x1)
+ xs += (x - x1);
+
+ if (ta->bar_x == NULL && ta->scroll_x != 0 &&
+ ta->flags & TEXTAREA_MULTILINE) {
+ /* Scrollbar removed, set to zero */
ta->scroll_x = 0;
scrolled = true;
- } else if (xs != ta->scroll_x && !(ta->flags & TEXTAREA_MULTILINE)) {
- ta->scroll_x = xs;
- scrolled = true;
+ } else if (xs != ta->scroll_x) {
+ /* Scrolled, set new pos. */
+ if (ta->bar_x != NULL) {
+ scrollbar_set(ta->bar_x, xs, false);
+ xs = scrollbar_get_offset(ta->bar_x);
+ if (xs != ta->scroll_x) {
+ ta->scroll_x = xs;
+ scrolled = true;
+ }
+
+ } else if (!(ta->flags & TEXTAREA_MULTILINE)) {
+ ta->scroll_x = xs;
+ scrolled = true;
+
+ }
}
/* check and change vertical scroll */
if (ta->flags & TEXTAREA_MULTILINE) {
- /* vertical scroll; centre caret */
- ys += y - yc;
+ scrollbar_width = (ta->bar_x == NULL) ? 0 : SCROLLBAR_WIDTH;
+ y0 = 0;
+ y1 = ta->vis_height - 2 * ta->border_width -
+ ta->pad_top - ta->pad_bottom;
- /* force back into range */
- if (ys < 0)
- ys = 0;
- else if (ys > ta->v_extent - (y1 - y0))
- ys = ta->v_extent - (y1 - y0);
+ /* Adjust scroll pos for reduced extents */
+ vis = ta->vis_height - 2 * ta->border_width - scrollbar_width;
+ if (ta->v_extent - ys < vis)
+ ys -= vis - (ta->v_extent - ys);
+
+ /* Get caret pos on screen */
+ y = ta->caret_y - ys;
+
+ /* scroll as required */
+ if (y < y0)
+ ys += (y - y0);
+ else if (y + ta->line_height > y1)
+ ys += (y + ta->line_height - y1);
- /* If scrolled, set new pos. */
if (ys != ta->scroll_y && ta->bar_y != NULL) {
+ /* Scrolled, set new pos. */
scrollbar_set(ta->bar_y, ys, false);
ys = scrollbar_get_offset(ta->bar_y);
if (ys != ta->scroll_y) {
@@ -329,6 +345,7 @@ static bool textarea_scroll_visible(struct textarea *ta)
}
} else if (ta->bar_y == NULL && ta->scroll_y != 0) {
+ /* Scrollbar removed, set to zero */
ta->scroll_y = 0;
scrolled = true;
}
@@ -361,6 +378,18 @@ static void textarea_scrollbar_callback(void *client_data,
msg.data.redraw.y1 = ta->vis_height;
ta->callback(ta->data, &msg);
+
+ if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
+ /* Tell client where caret should be placed */
+ msg.ta = ta;
+ msg.type = TEXTAREA_MSG_MOVED_CARET;
+ msg.data.caret.hidden = false;
+ msg.data.caret.x = ta->caret_x - ta->scroll_x;
+ msg.data.caret.y = ta->caret_y - ta->scroll_y;
+ msg.data.caret.height = ta->line_height;
+
+ ta->callback(ta->data, &msg);
+ }
break;
case SCROLLBAR_MSG_SCROLL_START:
@@ -421,6 +450,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
LOG(("malloc failed"));
return false;
}
+ ta->lines_alloc_size = LINE_CHUNK_SIZE;
}
if (!(ta->flags & TEXTAREA_MULTILINE)) {
@@ -471,7 +501,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
if (x > w)
w = x;
- ta->h_extent = w + ta->pad_left - ta->pad_right;
+ ta->h_extent = w + ta->pad_left + ta->pad_right;
ta->line_count = 1;
return true;
@@ -489,7 +519,10 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
do {
/* Set line count to start point */
- line = start;
+ if (restart)
+ line = 0;
+ else
+ line = start;
/* Find available width */
avail_width = ta->vis_width - 2 * ta->border_width -
@@ -498,6 +531,14 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
avail_width = 0;
h_extent = avail_width;
+ if (ta->text.len == 1) {
+ /* Handle empty textarea */
+ assert(ta->text.data[0] == '\0');
+ ta->lines[line].b_start = 0;
+ ta->lines[line++].b_length = 0;
+ ta->line_count = 1;
+ }
+
restart = false;
for (len = ta->text.len - 1, text = ta->text.data; len > 0;
len -= b_off, text += b_off) {
@@ -536,9 +577,11 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
ta->line_height;
}
- if (line > 0 && line % LINE_CHUNK_SIZE == 0) {
+ /* Ensure enough storage for lines data */
+ if (line > ta->lines_alloc_size - 2) {
+ /* Up to two lines my be added in a pass */
struct line_info *temp = realloc(ta->lines,
- (line + LINE_CHUNK_SIZE) *
+ (line + 2 + LINE_CHUNK_SIZE) *
sizeof(struct line_info));
if (temp == NULL) {
LOG(("realloc failed"));
@@ -546,6 +589,8 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
}
ta->lines = temp;
+ ta->lines_alloc_size = line + 2 +
+ LINE_CHUNK_SIZE;
}
if (para_end == text + b_off && *para_end == '\n') {
@@ -658,7 +703,6 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
* \param ta Text area
* \param x X coordinate
* \param y Y coordinate
- * \param b_off Updated to byte offset
* \param c_off Updated to character offset
*/
static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
@@ -699,9 +743,11 @@ static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
* following line, which is undesirable.
*/
if (ta->flags & TEXTAREA_MULTILINE &&
+ ta->show->data[ta->lines[line].b_start +
+ ta->lines[line].b_length] > 0 &&
bpos == (unsigned)ta->lines[line].b_length &&
ta->show->data[ta->lines[line].b_start +
- ta->lines[line].b_length - 1] == ' ')
+ ta->lines[line].b_length - 1] == ' ')
bpos--;
/* Get character position */
@@ -948,14 +994,15 @@ static bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse,
/* exported interface, documented in textarea.h */
-struct textarea *textarea_create(const textarea_setup *setup,
+struct textarea *textarea_create(const textarea_flags flags,
+ const textarea_setup *setup,
textarea_client_callback callback, void *data)
{
struct textarea *ret;
/* Sanity check flags */
- assert(!(setup->flags & TEXTAREA_MULTILINE &&
- setup->flags & TEXTAREA_PASSWORD));
+ assert(!(flags & TEXTAREA_MULTILINE &&
+ flags & TEXTAREA_PASSWORD));
if (callback == NULL) {
LOG(("no callback provided"));
@@ -971,7 +1018,7 @@ struct textarea *textarea_create(const textarea_setup *setup,
ret->callback = callback;
ret->data = data;
- ret->flags = setup->flags;
+ ret->flags = flags;
ret->vis_width = setup->width;
ret->vis_height = setup->height;
@@ -1008,7 +1055,7 @@ struct textarea *textarea_create(const textarea_setup *setup,
ret->text.len = 1;
ret->text.utf8_len = 0;
- if (setup->flags & TEXTAREA_PASSWORD) {
+ if (flags & TEXTAREA_PASSWORD) {
ret->password.data = malloc(64);
if (ret->password.data == NULL) {
LOG(("malloc failed"));
@@ -1032,10 +1079,9 @@ struct textarea *textarea_create(const textarea_setup *setup,
ret->show = &ret->text;
}
- ret->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.2),
- FMUL(nscss_screen_dpi,
- INTTOFIX((setup->text.size /
- FONT_SIZE_SCALE))))), F_72));
+ ret->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.3),
+ FMUL(nscss_screen_dpi, INTTOFIX((setup->text.size))))),
+ FONT_SIZE_SCALE * F_72));
ret->caret_pos.line = ret->caret_pos.char_off = -1;
ret->caret_x = 0;
@@ -1045,6 +1091,9 @@ struct textarea *textarea_create(const textarea_setup *setup,
ret->line_count = 0;
ret->lines = NULL;
+ ret->lines_alloc_size = 0;
+
+ textarea_reflow(ret, 0);
return ret;
}
@@ -1093,6 +1142,52 @@ bool textarea_set_text(struct textarea *ta, const char *text)
/* exported interface, documented in textarea.h */
+bool textarea_drop_text(struct textarea *ta, const char *text,
+ size_t text_length)
+{
+ struct textarea_msg msg;
+ unsigned int caret_pos;
+ size_t text_chars;
+
+ if (ta->flags & TEXTAREA_READONLY)
+ return false;
+
+ if (text == NULL)
+ return false;
+
+ text_chars = utf8_bounded_length(text, text_length);
+ caret_pos = textarea_get_caret(ta);
+
+ if (ta->sel_start != -1) {
+ if (!textarea_replace_text(ta, ta->sel_start, ta->sel_end,
+ text, text_length, false))
+ return false;
+
+ caret_pos = ta->sel_start + text_chars;
+ ta->sel_start = ta->sel_end = -1;
+ } else {
+ if (!textarea_replace_text(ta, caret_pos, caret_pos,
+ text, text_length, false))
+ return false;
+ caret_pos += text_chars;
+ }
+
+ textarea_set_caret(ta, caret_pos);
+
+ msg.ta = ta;
+ msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
+ msg.data.redraw.x0 = 0;
+ msg.data.redraw.y0 = 0;
+ msg.data.redraw.x1 = ta->vis_width;
+ msg.data.redraw.y1 = ta->vis_height;
+
+ ta->callback(ta->data, &msg);
+
+ return true;
+}
+
+
+/* exported interface, documented in textarea.h */
int textarea_get_text(struct textarea *ta, char *buf, unsigned int len)
{
if (buf == NULL && len == 0) {
@@ -1202,17 +1297,19 @@ bool textarea_set_caret(struct textarea *ta, int caret)
x += ta->border_width + ta->pad_left;
ta->caret_x = x;
- y = ta->line_height * ta->caret_pos.line;
+ y = ta->line_height * ta->caret_pos.line + text_y_offset;
ta->caret_y = y;
- if (!textarea_scroll_visible(ta)) {
- /* No scroll, just caret moved, redraw it */
+ if (!textarea_scroll_visible(ta) &&
+ ta->flags & TEXTAREA_INTERNAL_CARET) {
+ /* Didn't scroll, just moved caret.
+ * Caret is internal caret, redraw it */
x -= ta->scroll_x;
y -= ta->scroll_y;
x0 = max(x - 1, ta->border_width);
- y0 = max(y + text_y_offset, 0);
+ y0 = max(y, 0);
x1 = min(x + 1, ta->vis_width - ta->border_width);
- y1 = min(y + ta->line_height + text_y_offset,
+ y1 = min(y + ta->line_height,
ta->vis_height);
width = x1 - x0;
@@ -1229,6 +1326,26 @@ bool textarea_set_caret(struct textarea *ta, int caret)
ta->callback(ta->data, &msg);
}
}
+
+ if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
+ /* Tell client where caret should be placed */
+ msg.ta = ta;
+ msg.type = TEXTAREA_MSG_MOVED_CARET;
+ msg.data.caret.hidden = false;
+ msg.data.caret.x = x - ta->scroll_x;
+ msg.data.caret.y = y - ta->scroll_y;
+ msg.data.caret.height = ta->line_height;
+
+ ta->callback(ta->data, &msg);
+ }
+
+ } else if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
+ /* Caret hidden, and client is responsible: tell client */
+ msg.ta = ta;
+ msg.type = TEXTAREA_MSG_MOVED_CARET;
+ msg.data.caret.hidden = true;
+
+ ta->callback(ta->data, &msg);
}
return true;
@@ -1248,6 +1365,9 @@ int textarea_get_caret(struct textarea *ta)
if (ta->text.utf8_len == 0)
return 0;
+ if (ta->caret_pos.line >= ta->line_count)
+ return ta->text.utf8_len;
+
/* Calculate character offset of this line's start */
for (b_off = 0; b_off < ta->lines[ta->caret_pos.line].b_start;
b_off = utf8_next(ta->text.data, ta->text.len, b_off))
@@ -1258,19 +1378,20 @@ int textarea_get_caret(struct textarea *ta)
/* exported interface, documented in textarea.h */
-void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
+void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
const struct rect *clip, const struct redraw_context *ctx)
{
- struct textarea_msg msg;
const struct plotter_table *plot = ctx->plot;
- int line0, line1, line, left, right;
+ int line0, line1, line, left, right, line_y;
int chars, text_y_offset, text_y_offset_baseline;
unsigned int c_pos, c_len, c_len_part, b_start, b_end, line_len;
unsigned int sel_start, sel_end;
char *line_text;
struct rect r, s;
bool selected = false;
- plot_font_style_t *fstyle;
+ plot_font_style_t fstyle;
+ int fsize = ta->fstyle.size;
+ int line_height = ta->line_height;
plot_style_t plot_style_fill_bg = {
.stroke_type = PLOT_OP_TYPE_NONE,
.stroke_width = 0,
@@ -1308,10 +1429,17 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
r.x0 = x;
if (r.y0 < y)
r.y0 = y;
- if (r.x1 > x + ta->vis_width)
- r.x1 = x + ta->vis_width;
- if (r.y1 > y + ta->vis_height)
- r.y1 = y + ta->vis_height;
+ if (scale == 1.0) {
+ if (r.x1 > x + ta->vis_width)
+ r.x1 = x + ta->vis_width;
+ if (r.y1 > y + ta->vis_height)
+ r.y1 = y + ta->vis_height;
+ } else {
+ if (r.x1 > x + ta->vis_width * scale)
+ r.x1 = x + ta->vis_width * scale;
+ if (r.y1 > y + ta->vis_height * scale)
+ r.y1 = y + ta->vis_height * scale;
+ }
plot->clip(&r);
if (ta->border_col != NS_TRANSPARENT &&
@@ -1329,16 +1457,32 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
&plot_style_fill_bg);
}
- if (r.x0 < x + ta->border_width)
- r.x0 = x + ta->border_width;
- if (r.x1 > x + ta->vis_width - ta->border_width)
- r.x1 = x + ta->vis_width - ta->border_width;
- if (r.y0 < y + ta->border_width)
- r.y0 = y + ta->border_width;
- if (r.y1 > y + ta->vis_height - ta->border_width -
- (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0))
- r.y1 = y + ta->vis_height - ta->border_width -
- (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0);
+ if (scale == 1.0) {
+ if (r.x0 < x + ta->border_width)
+ r.x0 = x + ta->border_width;
+ if (r.x1 > x + ta->vis_width - ta->border_width)
+ r.x1 = x + ta->vis_width - ta->border_width;
+ if (r.y0 < y + ta->border_width)
+ r.y0 = y + ta->border_width;
+ if (r.y1 > y + ta->vis_height - ta->border_width -
+ (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0))
+ r.y1 = y + ta->vis_height - ta->border_width -
+ (ta->bar_x != NULL ? SCROLLBAR_WIDTH :
+ 0);
+ } else {
+ if (r.x0 < x + ta->border_width * scale)
+ r.x0 = x + ta->border_width * scale;
+ if (r.x1 > x + (ta->vis_width - ta->border_width) * scale)
+ r.x1 = x + (ta->vis_width - ta->border_width) * scale;
+ if (r.y0 < y + ta->border_width * scale)
+ r.y0 = y + ta->border_width * scale;
+ if (r.y1 > y + (ta->vis_height - ta->border_width -
+ (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0)) *
+ scale)
+ r.y1 = y + (ta->vis_height - ta->border_width -
+ (ta->bar_x != NULL ? SCROLLBAR_WIDTH :
+ 0) * scale);
+ }
if (line0 > 0)
c_pos = utf8_bounded_length(ta->show->data,
@@ -1359,13 +1503,23 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
text_y_offset_baseline += (vis_height * 3 + 2) / 4;
}
+ if (scale != 1.0) {
+ text_y_offset *= scale;
+ text_y_offset_baseline *= scale;
+
+ fsize *= scale;
+ line_height *= scale;
+ }
+
plot_style_fill_bg.fill_colour = ta->sel_fstyle.background;
for (line = line0; (line <= line1) &&
(y + line * ta->line_height <= r.y1 + ta->scroll_y);
line++) {
- if (ta->lines[line].b_length == 0)
+ if (ta->lines[line].b_length == 0) {
+ c_pos++;
continue;
+ }
/* reset clip rectangle */
plot->clip(&r);
@@ -1387,30 +1541,31 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
/* rest of line unselected */
selected = false;
c_len_part = c_len;
- fstyle = &ta->fstyle;
+ fstyle = ta->fstyle;
} else if (sel_start <= c_pos &&
sel_end > c_pos + c_len) {
/* rest of line selected */
selected = true;
c_len_part = c_len;
- fstyle = &ta->sel_fstyle;
+ fstyle = ta->sel_fstyle;
} else if (sel_start > c_pos) {
/* next part of line unselected */
selected = false;
c_len_part = sel_start - c_pos;
- fstyle = &ta->fstyle;
+ fstyle = ta->fstyle;
} else if (sel_end > c_pos) {
/* next part of line selected */
selected = true;
c_len_part = sel_end - c_pos;
- fstyle = &ta->sel_fstyle;
+ fstyle = ta->sel_fstyle;
} else {
assert(0);
}
+ fstyle.size = fsize;
line_text = &(ta->show->data[ta->lines[line].b_start]);
line_len = ta->lines[line].b_length;
@@ -1424,7 +1579,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
/* find clip left/right for this part of line */
left = right;
- nsfont.font_width(&ta->fstyle, line_text,
+ nsfont.font_width(&fstyle, line_text,
b_end, &right);
right += x + ta->border_width + ta->pad_left -
ta->scroll_x;
@@ -1435,27 +1590,31 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
s.x0 = left;
if (s.x1 > right)
s.x1 = right;
+
plot->clip(&s);
+ line_y = line * ta->line_height - ta->scroll_y;
+
+ if (scale != 1.0) {
+ line_y *= scale;
+ }
+
if (selected) {
/* draw selection fill */
- plot->rectangle(s.x0,
- y + line * ta->line_height + 1 -
- ta->scroll_y + text_y_offset,
- s.x1,
- y + (line + 1) * ta->line_height + 1 -
- ta->scroll_y + text_y_offset,
+ plot->rectangle(s.x0, y + line_y +
+ text_y_offset,
+ s.x1, y + line_y + line_height +
+ text_y_offset,
&plot_style_fill_bg);
}
/* draw text */
plot->text(x + ta->border_width + ta->pad_left -
ta->scroll_x,
- y + line * ta->line_height +
- text_y_offset_baseline - ta->scroll_y,
+ y + line_y + text_y_offset_baseline,
ta->show->data +
ta->lines[line].b_start,
- ta->lines[line].b_length, fstyle);
+ ta->lines[line].b_length, &fstyle);
c_pos += c_len_part;
c_len -= c_len_part;
@@ -1475,7 +1634,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
if ((ta->sel_end == -1 || ta->sel_start == ta->sel_end) &&
ta->caret_pos.char_off >= 0) {
/* There is no selection, and caret visible: show caret */
- int caret_y = y - ta->scroll_y + ta->caret_y + text_y_offset;
+ int caret_y = y - ta->scroll_y + ta->caret_y;
if (ta->flags & TEXTAREA_INTERNAL_CARET) {
/* Render our own caret */
@@ -1483,39 +1642,22 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
x - ta->scroll_x + ta->caret_x,
caret_y + ta->line_height,
&pstyle_stroke_caret);
- } else {
- /* Tell client where caret should be placed */
- msg.ta = ta;
- msg.type = TEXTAREA_MSG_MOVED_CARET;
- msg.data.caret.hidden = false;
- msg.data.caret.x = x - ta->scroll_x + ta->caret_x;
- msg.data.caret.y = caret_y;
- msg.data.caret.height = ta->line_height;
-
- ta->callback(ta->data, &msg);
}
- } else if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
- /* Caret hidden, and client is responsible: tell client */
- msg.ta = ta;
- msg.type = TEXTAREA_MSG_MOVED_CARET;
- msg.data.caret.hidden = true;
-
- ta->callback(ta->data, &msg);
}
if (ta->bar_x != NULL)
scrollbar_redraw(ta->bar_x,
- x + ta->border_width,
- y + ta->vis_height - ta->border_width -
+ x / scale + ta->border_width,
+ y / scale + ta->vis_height - ta->border_width -
SCROLLBAR_WIDTH,
- clip, 1.0, ctx);
+ clip, scale, ctx);
if (ta->bar_y != NULL)
scrollbar_redraw(ta->bar_y,
- x + ta->vis_width - ta->border_width -
+ x / scale + ta->vis_width - ta->border_width -
SCROLLBAR_WIDTH,
- y + ta->border_width,
- clip, 1.0, ctx);
+ y / scale + ta->border_width,
+ clip, scale, ctx);
}
@@ -1584,26 +1726,69 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
caret = ta->sel_start;
ta->sel_start = ta->sel_end = -1;
- redraw = true;
} else if (caret > 0) {
if (!textarea_replace_text(ta,
caret - 1,
caret, "", 0, false))
return false;
caret--;
- redraw = true;
}
+ redraw = true;
break;
+ case KEY_CR:
case KEY_NL:
if (readonly)
break;
- if(!textarea_insert_text(ta, caret, "\n", 1))
- return false;
- caret++;
- ta->sel_start = ta->sel_end = -1;
+
+ if (ta->sel_start != -1) {
+ if (!textarea_replace_text(ta,
+ ta->sel_start, ta->sel_end,
+ "\n", 1, false))
+ return false;
+
+ caret = ta->sel_start + 1;
+ ta->sel_start = ta->sel_end = -1;
+ } else {
+ if (!textarea_replace_text(ta,
+ caret, caret,
+ "\n", 1, false))
+ return false;
+ caret++;
+ }
redraw = true;
break;
case KEY_CUT_LINE:
+ /* Not actually CUT to clipboard, just delete */
+ if (readonly)
+ break;
+ if (ta->sel_start != -1) {
+ if (!textarea_replace_text(ta,
+ ta->sel_start,
+ ta->sel_end, "", 0, false))
+ return false;
+ ta->sel_start = ta->sel_end = -1;
+ } else {
+ if (ta->lines[line].b_length != 0) {
+ /* Delete line */
+ b_off = ta->lines[line].b_start;
+ b_len = ta->lines[line].b_length;
+ l_len = utf8_bounded_length(
+ &(ta->text.data[b_off]),
+ b_len);
+ caret -= ta->caret_pos.char_off;
+ if (!textarea_replace_text(ta, caret,
+ caret + l_len, "", 0,
+ false))
+ return false;
+ } else if (caret < ta->text.utf8_len) {
+ /* Delete blank line */
+ if (!textarea_replace_text(ta,
+ caret, caret + 1, "", 0,
+ false))
+ return false;
+ }
+ }
+ redraw = true;
break;
case KEY_PASTE:
{
@@ -1629,7 +1814,6 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
caret = ta->sel_start + clipboard_chars;
ta->sel_start = ta->sel_end = -1;
- redraw = true;
} else {
if (!textarea_replace_text(ta,
caret, caret,
@@ -1637,8 +1821,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
false))
return false;
caret += clipboard_chars;
- redraw = true;
}
+ redraw = true;
free(clipboard);
}
@@ -1702,38 +1886,37 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
- if (ta->flags & TEXTAREA_MULTILINE) {
- line--;
- if (line < 0)
- line = 0;
- if (line == ta->caret_pos.line)
- break;
+ if (!(ta->flags & TEXTAREA_MULTILINE))
+ break;
- b_off = ta->lines[line].b_start;
- b_len = ta->lines[line].b_length;
+ line--;
+ if (line < 0)
+ line = 0;
+ if (line == ta->caret_pos.line)
+ break;
- c_line = ta->caret_pos.line;
- c_chars = ta->caret_pos.char_off;
+ b_off = ta->lines[line].b_start;
+ b_len = ta->lines[line].b_length;
- if (ta->text.data[b_off + b_len - 1] == ' '
- && line < ta->line_count - 1)
- b_len--;
+ c_line = ta->caret_pos.line;
+ c_chars = ta->caret_pos.char_off;
- l_len = utf8_bounded_length(
- &(ta->text.data[b_off]),
- b_len);
+ if (b_len > 0 && ta->text.data[b_off + b_len - 1] == ' '
+ && line < ta->line_count - 1)
+ b_len--;
+ l_len = utf8_bounded_length(&(ta->text.data[b_off]),
+ b_len);
- ta->caret_pos.line = line;
- ta->caret_pos.char_off = min(l_len,
- (unsigned)
- ta->caret_pos.char_off);
+ ta->caret_pos.line = line;
+ ta->caret_pos.char_off = min(l_len,
+ (unsigned)ta->caret_pos.char_off);
- caret = textarea_get_caret(ta);
+ caret = textarea_get_caret(ta);
+
+ ta->caret_pos.line = c_line;
+ ta->caret_pos.char_off = c_chars;
- ta->caret_pos.line = c_line;
- ta->caret_pos.char_off = c_chars;
- }
break;
case KEY_PAGE_DOWN:
if (readonly)
@@ -1753,38 +1936,37 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
- if (ta->flags & TEXTAREA_MULTILINE) {
- line++;
- if (line > ta->line_count - 1)
- line = ta->line_count - 1;
- if (line == ta->caret_pos.line)
- break;
+ if (!(ta->flags & TEXTAREA_MULTILINE))
+ break;
- b_off = ta->lines[line].b_start;
- b_len = ta->lines[line].b_length;
+ line++;
+ if (line > ta->line_count - 1)
+ line = ta->line_count - 1;
+ if (line == ta->caret_pos.line)
+ break;
- c_line = ta->caret_pos.line;
- c_chars = ta->caret_pos.char_off;
+ b_off = ta->lines[line].b_start;
+ b_len = ta->lines[line].b_length;
- if (ta->text.data[b_off + b_len - 1] == ' '
- && line < ta->line_count - 1)
- b_len--;
+ c_line = ta->caret_pos.line;
+ c_chars = ta->caret_pos.char_off;
- l_len = utf8_bounded_length(
- &(ta->text.data[b_off]),
- b_len);
+ if (ta->text.data[b_off + b_len - 1] == ' ' &&
+ line < ta->line_count - 1)
+ b_len--;
+ l_len = utf8_bounded_length(&(ta->text.data[b_off]),
+ b_len);
- ta->caret_pos.line = line;
- ta->caret_pos.char_off = min(l_len,
- (unsigned)
- ta->caret_pos.char_off);
+ ta->caret_pos.line = line;
+ ta->caret_pos.char_off = min(l_len,
+ (unsigned)ta->caret_pos.char_off);
- caret = textarea_get_caret(ta);
+ caret = textarea_get_caret(ta);
+
+ ta->caret_pos.line = c_line;
+ ta->caret_pos.char_off = c_chars;
- ta->caret_pos.line = c_line;
- ta->caret_pos.char_off = c_chars;
- }
break;
case KEY_DELETE_RIGHT:
if (readonly)
@@ -1865,8 +2047,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
ta->sel_start = ta->sel_end = -1;
} else {
- b_off = ta->lines[ta->caret_pos.line].b_start;
- b_len = ta->lines[ta->caret_pos.line].b_length;
+ b_off = ta->lines[line].b_start;
+ b_len = ta->lines[line].b_length;
l_len = utf8_bounded_length(
&(ta->text.data[b_off]),
b_len);
@@ -1899,8 +2081,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
}
- if (caret != caret_init)
+ if (caret != caret_init || redraw)
textarea_set_caret(ta, caret);
+
//TODO:redraw only the important part
if (redraw) {
msg.ta = ta;
@@ -2006,7 +2189,8 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
return textarea_select_fragment(ta);
}
- } else if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_HOLDING_1)) {
+ } else if (mouse & BROWSER_MOUSE_DRAG_1) {
+ /* Selection start */
textarea_get_xy_offset(ta, x, y, &c_off);
c_start = ta->drag_start_char;
c_end = c_off;
@@ -2019,6 +2203,30 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
ta->callback(ta->data, &msg);
return textarea_select(ta, c_start, c_end);
+ } else if (mouse & BROWSER_MOUSE_HOLDING_1 &&
+ ta->drag_info.type == TEXTAREA_DRAG_SELECTION) {
+ /* Selection track */
+ int scrx = 0;
+ int scry = 0;
+
+ textarea_get_xy_offset(ta, x, y, &c_off);
+ c_start = ta->drag_start_char;
+ c_end = c_off;
+
+ /* selection auto-scroll */
+ if (x < 0)
+ scrx = x / 4;
+ else if (x > ta->vis_width)
+ scrx = (x - ta->vis_width) / 4;
+
+ if (y < 0)
+ scry = y / 4;
+ else if (y > ta->vis_height)
+ scry = (y - ta->vis_height) / 4;
+
+ textarea_scroll(ta, scrx, scry);
+
+ return textarea_select(ta, c_start, c_end);
}
return true;
@@ -2038,18 +2246,37 @@ void textarea_get_dimensions(struct textarea *ta, int *width, int *height)
/* exported interface, documented in textarea.h */
void textarea_set_dimensions(struct textarea *ta, int width, int height)
{
- struct textarea_msg msg;
+ ta->vis_width = width;
+ ta->vis_height = height;
+ textarea_reflow(ta, 0);
+}
+
+/* exported interface, documented in textarea.h */
+void textarea_set_layout(struct textarea *ta, int width, int height,
+ int top, int right, int bottom, int left)
+{
ta->vis_width = width;
ta->vis_height = height;
+ ta->pad_top = top;
+ ta->pad_right = right + ((ta->bar_y == NULL) ? 0 : SCROLLBAR_WIDTH);
+ ta->pad_bottom = bottom + ((ta->bar_x == NULL) ? 0 : SCROLLBAR_WIDTH);
+ ta->pad_left = left;
textarea_reflow(ta, 0);
+}
- msg.ta = ta;
- msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
- msg.data.redraw.x0 = 0;
- msg.data.redraw.y0 = 0;
- msg.data.redraw.x1 = ta->vis_width;
- msg.data.redraw.y1 = ta->vis_height;
- ta->callback(ta->data, &msg);
+/* exported interface, documented in textarea.h */
+bool textarea_scroll(struct textarea *ta, int scrx, int scry)
+{
+ bool handled_scroll = false;
+
+ if (ta->bar_x != NULL && scrx != 0 &&
+ scrollbar_scroll(ta->bar_x, scrx))
+ handled_scroll = true;
+ if (ta->bar_y != NULL && scry != 0 &&
+ scrollbar_scroll(ta->bar_y, scry))
+ handled_scroll = true;
+
+ return handled_scroll;
}