Fix single line textareas, improve display of multiline ones.

svn path=/trunk/netsurf/; revision=2732
This commit is contained in:
Richard Wilson 2006-07-11 23:04:13 +00:00
parent 806fc97126
commit 06429e69b5
2 changed files with 146 additions and 142 deletions

View File

@ -30,6 +30,9 @@
#include "netsurf/utils/log.h"
#include "netsurf/utils/utf8.h"
#define MARGIN_LEFT 8
#define MARGIN_RIGHT 8
struct line_info {
unsigned int b_start; /**< Byte offset of line start */
unsigned int b_length; /**< Byte length of line */
@ -56,7 +59,8 @@ static struct text_area {
char *font_family; /**< Font family of text */
unsigned int font_size; /**< Font size (16ths/pt) */
int line_height; /**< Height of a line, given font size */
int line_height; /**< Total height of a line, given font size */
int line_spacing; /**< Height of line spacing, given font size */
unsigned int line_count; /**< Count of lines */
#define LINE_CHUNK_SIZE 256
@ -148,11 +152,16 @@ uintptr_t textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
ret->font_size = font_size ? font_size : 192 /* 12pt */;
/** \todo Better line height calculation */
ret->line_height = (int)(((ret->font_size * 1.25) / 16) * 2.0) + 1;
ret->line_height = (int)(((ret->font_size * 1.3) / 16) * 2.0) + 1;
ret->line_spacing = ret->line_height / 8;
ret->line_count = 0;
ret->lines = 0;
if (flags & TEXTAREA_READONLY)
text_area_definition.title_fg = 0xff;
else
text_area_definition.title_fg = wimp_COLOUR_BLACK;
error = xwimp_create_window(&text_area_definition, &ret->window);
if (error) {
LOG(("xwimp_create_window: 0x%x: %s",
@ -188,11 +197,18 @@ uintptr_t textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
state.w = ret->window;
state.visible.x1 = state.visible.x0 + istate.icon.extent.x1 -
ro_get_vscroll_width(ret->window);
state.visible.x0 += istate.icon.extent.x0;
ro_get_vscroll_width(ret->window) - state.xscroll;
state.visible.x0 += istate.icon.extent.x0 + 2 - state.xscroll;
state.visible.y0 = state.visible.y1 + istate.icon.extent.y0 +
ro_get_hscroll_height(ret->window);
state.visible.y1 += istate.icon.extent.y1;
ro_get_hscroll_height(ret->window) - state.yscroll;
state.visible.y1 += istate.icon.extent.y1 - 2 - state.yscroll;
if (flags & TEXTAREA_READONLY) {
state.visible.x0 += 2;
state.visible.x1 -= 4;
state.visible.y0 += 4;
state.visible.y1 -= 2;
}
/* set our width/height */
ret->vis_width = state.visible.x1 - state.visible.x0;
@ -222,12 +238,8 @@ uintptr_t textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
<< wimp_CHILD_YORIGIN_SHIFT |
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_LS_EDGE_SHIFT |
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
<< wimp_CHILD_BS_EDGE_SHIFT |
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
<< wimp_CHILD_RS_EDGE_SHIFT |
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
<< wimp_CHILD_TS_EDGE_SHIFT);
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_RS_EDGE_SHIFT);
if (error) {
LOG(("xwimp_open_window_nested: 0x%x: %s",
error->errnum, error->errmess));
@ -244,6 +256,9 @@ uintptr_t textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
text_areas->prev = ret;
text_areas = ret;
/* make available for immediate use */
textarea_reflow(ret, 0);
/* and register our event handlers */
ro_gui_wimp_event_register_mouse_click(ret->window,
textarea_mouse_click);
@ -498,6 +513,11 @@ void textarea_set_caret(uintptr_t self, unsigned int caret)
struct text_area *ta;
size_t c_len, b_off;
unsigned int i;
size_t index;
int x;
os_coord os_line_height;
rufl_code code;
os_error *error;
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
@ -521,12 +541,115 @@ void textarea_set_caret(uintptr_t self, unsigned int caret)
ta->caret_pos.line = i;
/* Finally, calculate the char. offset of the caret in this line */
/* Now calculate the char. offset of the caret in this line */
for (c_len = 0, ta->caret_pos.char_off = 0;
c_len < b_off - ta->lines[i].b_start;
c_len = utf8_next(ta->text + ta->lines[i].b_start,
ta->lines[i].b_length, c_len))
ta->caret_pos.char_off++;
/* Finally, redraw the WIMP caret */
index = textarea_get_caret(self);
os_line_height.x = 0;
os_line_height.y = (int)((float)(ta->line_height - ta->line_spacing) * 0.62) + 1;
ro_convert_pixels_to_os_units(&os_line_height, (os_mode)-1);
for (b_off = 0; index-- > 0; b_off = utf8_next(ta->text, ta->text_len, b_off))
; /* do nothing */
code = rufl_width(ta->font_family, rufl_WEIGHT_400, ta->font_size,
ta->text + ta->lines[ta->caret_pos.line].b_start,
b_off - ta->lines[ta->caret_pos.line].b_start, &x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
LOG(("rufl_width: 0x%x: %s",
rufl_fm_error->errnum,
rufl_fm_error->errmess));
else
LOG(("rufl_width: 0x%x", code));
return;
}
error = xwimp_set_caret_position(ta->window, -1, x + MARGIN_LEFT,
-((ta->caret_pos.line + 1) * ta->line_height) -
ta->line_height / 4 + ta->line_spacing,
os_line_height.y, -1);
if (error) {
LOG(("xwimp_set_caret_position: 0x%x: %s",
error->errnum, error->errmess));
return;
}
}
/**
* Set the caret's position
*
* \param self Text area
* \param x X position of caret on the screen
* \param y Y position of caret on the screen
*/
void textarea_set_caret_xy(uintptr_t self, int x, int y)
{
struct text_area *ta;
wimp_window_state state;
size_t b_off, c_off, temp;
int line;
os_coord os_line_height;
rufl_code code;
os_error *error;
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
LOG(("magic doesn't match"));
return;
}
if (ta->flags & TEXTAREA_READONLY)
return;
os_line_height.x = 0;
os_line_height.y = (int)((float)(ta->line_height - ta->line_spacing) * 0.62) + 1;
ro_convert_pixels_to_os_units(&os_line_height, (os_mode)-1);
state.w = ta->window;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
return;
}
x = x - (state.visible.x0 - state.xscroll) - MARGIN_LEFT;
y = (state.visible.y1 - state.yscroll) - y;
line = y / ta->line_height;
if (line < 0)
line = 0;
if (ta->line_count - 1 < (unsigned)line)
line = ta->line_count - 1;
code = rufl_x_to_offset(ta->font_family, rufl_WEIGHT_400,
ta->font_size,
ta->text + ta->lines[line].b_start,
ta->lines[line].b_length,
x, &b_off, &x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
LOG(("rufl_x_to_offset: 0x%x: %s",
rufl_fm_error->errnum,
rufl_fm_error->errmess));
else
LOG(("rufl_x_to_offset: 0x%x", code));
return;
}
for (temp = 0, c_off = 0; temp < b_off + ta->lines[line].b_start;
temp = utf8_next(ta->text, ta->text_len, temp))
c_off++;
textarea_set_caret((uintptr_t)ta, c_off);
}
/**
@ -608,7 +731,7 @@ void textarea_reflow(struct text_area *ta, unsigned int line)
if (!(ta->flags & TEXTAREA_MULTILINE)) {
/* Single line */
ta->lines[line_count].b_start = 0;
ta->lines[line_count++].b_length = ta->text_len;
ta->lines[line_count++].b_length = ta->text_len - 1;
ta->line_count = line_count;
@ -618,7 +741,8 @@ void textarea_reflow(struct text_area *ta, unsigned int line)
for (len = ta->text_len - 1, text = ta->text; len > 0;
len -= b_off, text += b_off) {
code = rufl_split(ta->font_family, rufl_WEIGHT_400,
ta->font_size, text, len, ta->vis_width,
ta->font_size, text, len,
ta->vis_width - MARGIN_LEFT - MARGIN_RIGHT,
&b_off, &x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
@ -691,7 +815,7 @@ void textarea_reflow(struct text_area *ta, unsigned int line)
extent.x0 = 0;
extent.y1 = 0;
extent.x1 = ta->vis_width;
extent.y0 = -ta->line_height * (line_count + 1);
extent.y0 = -ta->line_height * line_count - ta->line_spacing;
if (extent.y0 > (int)-ta->vis_height)
/* haven't filled window yet */
@ -789,75 +913,12 @@ void textarea_reflow(struct text_area *ta, unsigned int line)
bool textarea_mouse_click(wimp_pointer *pointer)
{
struct text_area *ta;
wimp_window_state state;
size_t b_off, c_off, temp;
int x, y, line;
os_coord os_line_height;
rufl_code code;
os_error *error;
ta = textarea_from_w(pointer->w);
if (!ta)
return false;
/** \todo modify for selection model */
if (ta->flags & TEXTAREA_READONLY)
return true;
os_line_height.x = 0;
os_line_height.y = (int)((float)ta->line_height * 0.6) + 1;
ro_convert_pixels_to_os_units(&os_line_height, (os_mode)-1);
state.w = pointer->w;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
return false;
}
x = pointer->pos.x - (state.visible.x0 - state.xscroll);
y = (state.visible.y1 - state.yscroll) - pointer->pos.y;
line = y / ta->line_height;
if (line < 0)
line = 0;
if (ta->line_count - 1 < (unsigned)line)
line = ta->line_count - 1;
code = rufl_x_to_offset(ta->font_family, rufl_WEIGHT_400,
ta->font_size,
ta->text + ta->lines[line].b_start,
ta->lines[line].b_length,
x, &b_off, &x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
LOG(("rufl_x_to_offset: 0x%x: %s",
rufl_fm_error->errnum,
rufl_fm_error->errmess));
else
LOG(("rufl_x_to_offset: 0x%x", code));
return false;
}
for (temp = 0, c_off = 0; temp < b_off + ta->lines[line].b_start;
temp = utf8_next(ta->text, ta->text_len, temp))
c_off++;
textarea_set_caret((uintptr_t)ta, c_off);
error = xwimp_set_caret_position(state.w, -1,
x,
-((ta->caret_pos.line + 1) * ta->line_height) -
ta->line_height / 4,
os_line_height.y, -1);
if (error) {
LOG(("xwimp_set_caret_position: 0x%x: %s",
error->errnum, error->errmess));
return false;
}
textarea_set_caret_xy((uintptr_t)ta, pointer->pos.x, pointer->pos.y);
return true;
}
@ -1020,74 +1081,16 @@ bool textarea_key_press(wimp_key *key)
{
wimp_draw update;
wimp_window_state state;
size_t b_off, index;
int x;
os_coord os_line_height;
rufl_code code;
unsigned int c_pos =
textarea_get_caret((uintptr_t)ta);
textarea_insert_text((uintptr_t)ta, c_pos, utf8);
textarea_set_caret((uintptr_t)ta, ++c_pos);
index = c_pos;
os_line_height.x = 0;
os_line_height.y =
(int)((float)ta->line_height * 0.6) + 1;
ro_convert_pixels_to_os_units(&os_line_height,
(os_mode)-1);
for (b_off = 0; index-- > 0;
b_off = utf8_next(ta->text,
ta->text_len, b_off))
; /* do nothing */
code = rufl_width(ta->font_family, rufl_WEIGHT_400,
ta->font_size,
ta->text + ta->lines[ta->caret_pos.
line].b_start,
b_off - ta->lines[ta->caret_pos.
line].b_start,
&x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
LOG(("rufl_width: 0x%x: %s",
rufl_fm_error->errnum,
rufl_fm_error->errmess));
else
LOG(("rufl_width: 0x%x", code));
return true;
}
state.w = ta->window;
error = xwimp_get_window_state(&state);
if (error) {
LOG(("xwimp_get_window_state: 0x%x: %s",
error->errnum, error->errmess));
return true;
}
error = xwimp_set_caret_position(ta->window, -1,
x,
-((ta->caret_pos.line + 1) *
ta->line_height) -
ta->line_height / 4,
os_line_height.y, -1);
if (error) {
LOG(("xwimp_set_caret_position: 0x%x: %s",
error->errnum, error->errmess));
return true;
}
update.w = ta->window;
update.box.x0 = 0;
update.box.y1 = 0;
update.box.x1 = ta->vis_width;
update.box.y0 =
-ta->line_height * (ta->line_count + 1);
update.box.y0 = -ta->line_height * (ta->line_count + 1);
textarea_redraw_internal(&update, true);
}
}
@ -1196,10 +1199,10 @@ void textarea_redraw_internal(wimp_draw *redraw, bool update)
ta->font_size,
ta->text + ta->lines[line].b_start,
ta->lines[line].b_length,
redraw->box.x0 - redraw->xscroll,
redraw->box.x0 - redraw->xscroll + MARGIN_LEFT,
redraw->box.y1 - redraw->yscroll -
((line + 1) *
ta->line_height),
ta->line_height - ta->line_spacing),
rufl_BLEND_FONT);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)

View File

@ -26,6 +26,7 @@ void textarea_insert_text(uintptr_t self, unsigned int index,
void textarea_replace_text(uintptr_t self, unsigned int start,
unsigned int end, const char *text);
void textarea_set_caret(uintptr_t self, unsigned int caret);
void textarea_set_caret_xy(uintptr_t self, int x, int y);
unsigned int textarea_get_caret(uintptr_t self);