diff options
author | Vincent Sanders <vince@kyllikki.org> | 2016-05-05 22:28:51 +0100 |
---|---|---|
committer | Vincent Sanders <vince@kyllikki.org> | 2016-05-15 13:44:34 +0100 |
commit | d21447d096a320a08b3efb2b8768fad0dcdcfd64 (patch) | |
tree | 1a83814b7c9e94b2f13c473261f23dd3a17dee64 /riscos/textarea.c | |
parent | 2cbb337756d9af5bda4d594964d446439f602551 (diff) | |
download | netsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.gz netsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.bz2 |
move frontends into sub directory
Diffstat (limited to 'riscos/textarea.c')
-rw-r--r-- | riscos/textarea.c | 1160 |
1 files changed, 0 insertions, 1160 deletions
diff --git a/riscos/textarea.c b/riscos/textarea.c deleted file mode 100644 index ecf3e0c3d..000000000 --- a/riscos/textarea.c +++ /dev/null @@ -1,1160 +0,0 @@ -/* - * Copyright 2006 John-Mark Bell <jmb202@ecs.soton.ac.uk> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** \file - * Single/Multi-line UTF-8 text area (implementation) - */ - -#include <inttypes.h> -#include <stdbool.h> -#include <stdint.h> -#include <string.h> -#include <swis.h> -#include <oslib/colourtrans.h> -#include <oslib/osbyte.h> -#include <oslib/serviceinternational.h> -#include <oslib/wimp.h> -#include <oslib/wimpspriteop.h> - -#include "utils/log.h" -#include "utils/utf8.h" -#include "desktop/browser.h" - -#include "riscos/gui.h" -#include "riscos/oslib_pre7.h" -#include "riscos/textarea.h" -#include "riscos/ucstables.h" -#include "riscos/wimp.h" -#include "riscos/wimp_event.h" -#include "riscos/wimputils.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 */ -}; - -struct text_area { -#define MAGIC (('T'<<24) | ('E'<<16) | ('X'<<8) | 'T') - unsigned int magic; /**< Magic word, for sanity */ - - unsigned int flags; /**< Textarea flags */ - unsigned int vis_width; /**< Visible width, in pixels */ - unsigned int vis_height; /**< Visible height, in pixels */ - wimp_w window; /**< Window handle */ - - char *text; /**< UTF-8 text */ - unsigned int text_alloc; /**< Size of allocated text */ - unsigned int text_len; /**< Length of text, in bytes */ - struct { - unsigned int line; /**< Line caret is on */ - unsigned int char_off; /**< Character index of caret */ - } caret_pos; -// unsigned int selection_start; /**< Character index of sel start */ -// unsigned int selection_end; /**< Character index of sel end */ - - wimp_w parent; /**< Parent window handle */ - wimp_i icon; /**< Parent icon handle */ - - char *font_family; /**< Font family of text */ - unsigned int font_size; /**< Font size (16ths/pt) */ - rufl_style font_style; /**< Font style (rufl) */ - 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 - struct line_info *lines; /**< Line info array */ - - struct text_area *next; /**< Next text area in list */ - struct text_area *prev; /**< Prev text area in list */ -}; - -static wimp_window text_area_definition = { - {0, 0, 16, 16}, - 0, - 0, - wimp_TOP, - wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_NO_BOUNDS, - wimp_COLOUR_BLACK, - wimp_COLOUR_LIGHT_GREY, - wimp_COLOUR_LIGHT_GREY, - wimp_COLOUR_VERY_LIGHT_GREY, - wimp_COLOUR_DARK_GREY, - wimp_COLOUR_MID_LIGHT_GREY, - wimp_COLOUR_CREAM, - 0, - {0, -16384, 16384, 0}, - wimp_ICON_TEXT | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED, - wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT, - wimpspriteop_AREA, - 1, - 1, - {""}, - 0, - {} -}; - -static void ro_textarea_reflow(struct text_area *ta, unsigned int line); -static bool ro_textarea_mouse_click(wimp_pointer *pointer); -static bool ro_textarea_key_press(wimp_key *key); -static void ro_textarea_redraw(wimp_draw *redraw); -static void ro_textarea_redraw_internal(wimp_draw *redraw, bool update); -static void ro_textarea_open(wimp_open *open); - -/** - * Create a text area - * - * \param parent Parent window - * \param icon Icon in parent window to replace - * \param flags Text area flags - * \param font_family RUfl font family to use, or NULL for default - * \param font_size Font size to use (pt * 16), or 0 for default - * \param font_style Font style to use, or 0 for default - * \return Opaque handle for textarea or 0 on error - */ -uintptr_t ro_textarea_create(wimp_w parent, wimp_i icon, unsigned int flags, - const char *font_family, unsigned int font_size, - rufl_style font_style) -{ - struct text_area *ret; - os_error *error; - - ret = malloc(sizeof(struct text_area)); - if (!ret) { - LOG("malloc failed"); - return 0; - } - - ret->parent = parent; - ret->icon = icon; - ret->magic = MAGIC; - ret->flags = flags; - ret->text = malloc(64); - if (!ret->text) { - LOG("malloc failed"); - free(ret); - return 0; - } - ret->text[0] = '\0'; - ret->text_alloc = 64; - ret->text_len = 1; - ret->caret_pos.line = ret->caret_pos.char_off = (unsigned int)-1; -// ret->selection_start = (unsigned int)-1; -// ret->selection_end = (unsigned int)-1; - ret->font_family = strdup(font_family ? font_family : "Corpus"); - if (!ret->font_family) { - LOG("strdup failed"); - free(ret->text); - free(ret); - return 0; - } - ret->font_size = font_size ? font_size : 192 /* 12pt */; - ret->font_style = font_style ? font_style : rufl_WEIGHT_400; - - /** \todo Better line height calculation */ - 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", error->errnum, error->errmess); - free(ret->font_family); - free(ret->text); - free(ret); - return 0; - } - - /* set the window dimensions */ - if (!ro_textarea_update((uintptr_t)ret)) { - ro_textarea_destroy((uintptr_t)ret); - return 0; - } - - /* and register our event handlers */ - ro_gui_wimp_event_set_user_data(ret->window, ret); - ro_gui_wimp_event_register_mouse_click(ret->window, - ro_textarea_mouse_click); - ro_gui_wimp_event_register_keypress(ret->window, - ro_textarea_key_press); - ro_gui_wimp_event_register_redraw_window(ret->window, - ro_textarea_redraw); - ro_gui_wimp_event_register_open_window(ret->window, - ro_textarea_open); - - return (uintptr_t)ret; -} - -/** - * Update the a text area following a change in the parent icon - * - * \param self Text area to update - */ -bool ro_textarea_update(uintptr_t self) -{ - struct text_area *ta; - wimp_window_state state; - wimp_icon_state istate; - os_box extent; - os_error *error; - - ta = (struct text_area *)self; - if (!ta || ta->magic != MAGIC) - return false; - - state.w = ta->parent; - error = xwimp_get_window_state(&state); - if (error) { - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); - return false; - } - - istate.w = ta->parent; - istate.i = ta->icon; - error = xwimp_get_icon_state(&istate); - if (error) { - LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); - return false; - } - - state.w = ta->window; - state.visible.x1 = state.visible.x0 + istate.icon.extent.x1 - - ro_get_vscroll_width(ta->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(ta->window) - state.yscroll; - state.visible.y1 += istate.icon.extent.y1 - 2 - state.yscroll; - - if (ta->flags & TEXTAREA_READONLY) { - state.visible.x0 += 2; - state.visible.x1 -= 4; - state.visible.y0 += 2; - state.visible.y1 -= 4; - } - - /* set our width/height */ - ta->vis_width = state.visible.x1 - state.visible.x0; - ta->vis_height = state.visible.y1 - state.visible.y0; - - /* Set window extent to visible area */ - extent.x0 = 0; - extent.y0 = -ta->vis_height; - extent.x1 = ta->vis_width; - extent.y1 = 0; - - error = xwimp_set_extent(ta->window, &extent); - if (error) { - LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess); - return false; - } - - /* and open the window */ - error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), ta->parent, - wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT - << wimp_CHILD_XORIGIN_SHIFT | - wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT - << wimp_CHILD_YORIGIN_SHIFT | - wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT - << wimp_CHILD_LS_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); - return false; - } - - /* reflow the text */ - ro_textarea_reflow(ta, 0); - return true; -} - -/** - * Destroy a text area - * - * \param self Text area to destroy - */ -void ro_textarea_destroy(uintptr_t self) -{ - struct text_area *ta; - os_error *error; - - ta = (struct text_area *)self; - if (!ta || ta->magic != MAGIC) - return; - - error = xwimp_delete_window(ta->window); - if (error) { - LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess); - } - - ro_gui_wimp_event_finalise(ta->window); - - free(ta->font_family); - free(ta->text); - free(ta); -} - -/** - * Set the text in a text area, discarding any current text - * - * \param self Text area - * \param text UTF-8 text to set text area's contents to - * \return true on success, false on memory exhaustion - */ -bool ro_textarea_set_text(uintptr_t self, const char *text) -{ - struct text_area *ta; - unsigned int len = strlen(text) + 1; - - ta = (struct text_area *)self; - if (!ta || ta->magic != MAGIC) { - LOG("magic doesn't match"); - return true; - } - - if (len >= ta->text_alloc) { - char *temp = realloc(ta->text, len + 64); - if (!temp) { - LOG("realloc failed"); - return false; - } - ta->text = temp; - ta->text_alloc = len+64; - } - - memcpy(ta->text, text, len); - ta->text_len = len; - - ro_textarea_reflow(ta, 0); - - return true; -} - -/** - * Extract the text from a text area - * - * \param self Text area - * \param buf Pointer to buffer to receive data, or NULL - * to read length required - * \param len Length (bytes) of buffer pointed to by buf, or 0 to read length - * \return Length (bytes) written/required or -1 on error - */ -int ro_textarea_get_text(uintptr_t self, char *buf, unsigned int len) -{ - struct text_area *ta; - - ta = (struct text_area *)self; - if (!ta || ta->magic != MAGIC) { - LOG("magic doesn't match"); - return -1; - } - - if (buf == NULL && len == 0) { - /* want length */ - return ta->text_len; - } - - if (len < ta->text_len) { - LOG("buffer too small"); - return -1; - } - - memcpy(buf, ta->text, ta->text_len); - - return ta->text_len; -} - -/** - * Insert text into the text area - * - * \param self Text area - * \param index 0-based character index to insert at - * \param text UTF-8 text to insert - */ -void ro_textarea_insert_text(uintptr_t self, unsigned int index, - const char *text) -{ - struct text_area *ta; - unsigned int b_len = strlen(text); - size_t b_off, c_len; - - ta = (struct text_area *)self; - if (!ta || ta->magic != MAGIC) { - LOG("magic doesn't match"); - return; - } - - c_len = utf8_length(ta->text); - - /* Find insertion point */ - if (index > c_len) - index = c_len; - - for (b_off = 0; index-- > 0; - b_off = utf8_next(ta->text, ta->text_len, b_off)) - ; /* do nothing */ - - if (b_len + ta->text_len >= ta->text_alloc) { - char *temp = realloc(ta->text, b_len + ta->text_len + 64); - if (!temp) { - LOG("realloc failed"); - return; - } - - ta->text = temp; - ta->text_alloc = b_len + ta->text_len + 64; - } - - /* Shift text following up */ - memmove(ta->text + b_off + b_len, ta->text + b_off, - ta->text_len - b_off); - /* Insert new text */ - memcpy(ta->text + b_off, text, b_len); - - ta->text_len += b_len; - - /** \todo calculate line to reflow from */ - ro_textarea_reflow(ta, 0); -} - -/** - * Replace text in a text area - * - * \param self Text area - * \param start Start character index of replaced section (inclusive) - * \param end End character index of replaced section (exclusive) - * \param text UTF-8 text to insert - */ -void ro_textarea_replace_text(uintptr_t self, unsigned int start, - unsigned int end, const char *text) -{ - struct text_area *ta; - int b_len = strlen(text); - size_t b_start, b_end, c_len, diff; - - ta = (struct text_area *)self; - if (!ta || ta->magic != MAGIC) { - LOG("magic doesn't match"); - return; - } - - c_len = utf8_length(ta->text); - - if (start > c_len) - start = c_len; - if (end > c_len) - end = c_len; - - if (start == end) - return ro_textarea_insert_text(self, start, text); - - if (start > end) { - int temp = end; - end = start; - start = temp; - } - - diff = end - start; - - for (b_start = 0; start-- > 0; - b_start = utf8_next(ta->text, ta->text_len, b_start)) - ; /* do nothing */ - - for (b_end = b_start; diff-- > 0; - b_end = utf8_next(ta->text, ta->text_len, b_end)) - ; /* do nothing */ - - if (b_len + ta->text_len - (b_end - b_start) >= ta->text_alloc) { - char *temp = realloc(ta->text, - b_len + ta->text_len - (b_end - b_start) + 64); - if (!temp) { - LOG("realloc failed"); - return; - } - - ta->text = temp; - ta->text_alloc = - b_len + ta->text_len - (b_end - b_start) + 64; - } - - /* Shift text following to new position */ - memmove(ta->text + b_start + b_len, ta->text + b_end, - ta->text_len - b_end); - - /* Insert new text */ - memcpy(ta->text + b_start, text, b_len); - - ta->text_len += b_len - (b_end - b_start); - - /** \todo calculate line to reflow from */ - ro_textarea_reflow(ta, 0); -} - -/** - * Set the caret's position - * - * \param self Text area - * \param caret 0-based character index to place caret at - */ -void ro_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) { - LOG("magic doesn't match"); - return; - } - - c_len = utf8_length(ta->text); - - if (caret > c_len) - caret = c_len; - - /* Find byte offset of caret position */ - for (b_off = 0; caret > 0; caret--) - b_off = utf8_next(ta->text, ta->text_len, b_off); - - /* Now find line in which byte offset appears */ - for (i = 0; i < ta->line_count - 1; i++) - if (ta->lines[i + 1].b_start > b_off) - break; - - ta->caret_pos.line = i; - - /* 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 = ro_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, ta->font_style, 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 ro_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, ta->font_style, - 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++; - - ro_textarea_set_caret((uintptr_t)ta, c_off); -} - -/** - * Get the caret's position - * - * \param self Text area - * \return 0-based character index of caret location, or -1 on error - */ -unsigned int ro_textarea_get_caret(uintptr_t self) -{ - struct text_area *ta; - size_t c_off = 0, b_off; - - ta = (struct text_area *)self; - if (!ta || ta->magic != MAGIC) { - LOG("magic doesn't match"); - return -1; - } - - /* 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, ta->text_len, b_off)) - c_off++; - - return c_off + ta->caret_pos.char_off; -} - -/** \todo Selection handling */ - -/** - * Reflow a text area from the given line onwards - * - * \param ta Text area to reflow - * \param line Line number to begin reflow on - */ -void ro_textarea_reflow(struct text_area *ta, unsigned int line) -{ - rufl_code code; - char *text; - unsigned int len; - size_t b_off; - int x; - char *space; - unsigned int line_count = 0; - os_box extent; - os_error *error; - - /** \todo pay attention to line parameter */ - /** \todo create horizontal scrollbar if needed */ - - ta->line_count = 0; - - if (!ta->lines) { - ta->lines = - malloc(LINE_CHUNK_SIZE * sizeof(struct line_info)); - if (!ta->lines) { - LOG("malloc failed"); - return; - } - } - - if (!(ta->flags & TEXTAREA_MULTILINE)) { - /* Single line */ - ta->lines[line_count].b_start = 0; - ta->lines[line_count++].b_length = ta->text_len - 1; - - ta->line_count = line_count; - - return; - } - - for (len = ta->text_len - 1, text = ta->text; len > 0; - len -= b_off, text += b_off) { - code = rufl_split(ta->font_family, ta->font_style, - 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) - 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; - } - - if (line_count > 0 && line_count % LINE_CHUNK_SIZE == 0) { - struct line_info *temp = realloc(ta->lines, - (line_count + LINE_CHUNK_SIZE) * - sizeof(struct line_info)); - if (!temp) { - LOG("realloc failed"); - return; - } - - ta->lines = temp; - } - - /* handle CR/LF */ - for (space = text; space < text + b_off; space++) { - if (*space == '\r' || *space == '\n') - break; - } - - if (space != text + b_off) { - /* Found newline; use it */ - ta->lines[line_count].b_start = text - ta->text; - ta->lines[line_count++].b_length = space - text; - - /* CRLF / LFCR pair */ - if (*space == '\r' && *(space + 1) == '\n') - space++; - else if (*space == '\n' && *(space + 1) == '\r') - space++; - - b_off = space + 1 - text; - - if (len - b_off == 0) { - /* reached end of input => add last line */ - ta->lines[line_count].b_start = - text + b_off - ta->text; - ta->lines[line_count++].b_length = 0; - } - - continue; - } - - if (len - b_off > 0) { - /* find last space (if any) */ - for (space = text + b_off; space > text; space--) - if (*space == ' ') - break; - - if (space != text) - b_off = space + 1 - text; - } - - ta->lines[line_count].b_start = text - ta->text; - ta->lines[line_count++].b_length = b_off; - } - - ta->line_count = line_count; - - /* and now update extent */ - extent.x0 = 0; - extent.y1 = 0; - extent.x1 = ta->vis_width; - extent.y0 = -ta->line_height * line_count - ta->line_spacing; - - if (extent.y0 > (int)-ta->vis_height) - /* haven't filled window yet */ - return; - - error = xwimp_set_extent(ta->window, &extent); - if (error) { - LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess); - return; - } - - /* Create vertical scrollbar if we don't already have one */ - if (!ro_gui_wimp_check_window_furniture(ta->window, - wimp_WINDOW_VSCROLL)) { - wimp_window_state state; - wimp_w parent; - bits linkage; - unsigned int vscroll_width; - - /* Save window parent & linkage flags */ - state.w = ta->window; - error = xwimp_get_window_state_and_nesting(&state, - &parent, &linkage); - if (error) { - LOG("xwimp_get_window_state_and_nesting: 0x%x: %s", error->errnum, error->errmess); - return; - } - - /* Now, attempt to create vertical scrollbar */ - ro_gui_wimp_update_window_furniture(ta->window, - wimp_WINDOW_VSCROLL, - wimp_WINDOW_VSCROLL); - - /* Get new window state */ - 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; - } - - /* Get scroll width */ - vscroll_width = ro_get_vscroll_width(NULL); - - /* Shrink width by difference */ - state.visible.x1 -= vscroll_width; - - /* and reopen window */ - error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), - parent, linkage); - if (error) { - LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess); - return; - } - - /* finally, update visible width */ - ta->vis_width -= vscroll_width; - - /* Now we've done that, we have to reflow the text area */ - ro_textarea_reflow(ta, 0); - } -} - -/** - * Handle mouse clicks in a text area - * - * \param pointer Mouse click state block - * \return true if click handled, false otherwise - */ -bool ro_textarea_mouse_click(wimp_pointer *pointer) -{ - struct text_area *ta; - - ta = (struct text_area *)ro_gui_wimp_event_get_user_data(pointer->w); - - ro_textarea_set_caret_xy((uintptr_t)ta, pointer->pos.x, pointer->pos.y); - return true; -} - -/** - * Handle key presses in a text area - * - * \param key Key pressed state block - * \return true if press handled, false otherwise - */ -bool ro_textarea_key_press(wimp_key *key) -{ - uint32_t c = (uint32_t) key->c; - wimp_key keypress; - struct text_area *ta; - bool redraw = false; - unsigned int c_pos; - - ta = (struct text_area *)ro_gui_wimp_event_get_user_data(key->w); - - if (ta->flags & TEXTAREA_READONLY) - return true; - - if (!(c & IS_WIMP_KEY || - (c <= 0x001f || (0x007f <= c && c <= 0x009f)))) { - /* normal character - insert */ - char utf8[7]; - size_t utf8_len; - - utf8_len = utf8_from_ucs4(c, utf8); - utf8[utf8_len] = '\0'; - - c_pos = ro_textarea_get_caret((uintptr_t)ta); - ro_textarea_insert_text((uintptr_t)ta, c_pos, utf8); - ro_textarea_set_caret((uintptr_t)ta, ++c_pos); - - redraw = true; - } else { - os_error *error; - /** \todo handle command keys */ - switch (c & ~IS_WIMP_KEY) { - case 8: /* Backspace */ - c_pos = ro_textarea_get_caret((uintptr_t)ta); - if (c_pos > 0) { - ro_textarea_replace_text((uintptr_t)ta, - c_pos - 1, c_pos, ""); - ro_textarea_set_caret((uintptr_t)ta, c_pos - 1); - redraw = true; - } - break; - case 21: /* Ctrl + U */ - ro_textarea_set_text((uintptr_t)ta, ""); - ro_textarea_set_caret((uintptr_t)ta, 0); - redraw = true; - break; - case wimp_KEY_DELETE: - c_pos = ro_textarea_get_caret((uintptr_t)ta); - if (os_version < RISCOS5 && c_pos > 0) { - ro_textarea_replace_text((uintptr_t)ta, - c_pos - 1, c_pos, ""); - ro_textarea_set_caret((uintptr_t)ta, c_pos - 1); - } else { - ro_textarea_replace_text((uintptr_t)ta, c_pos, - c_pos + 1, ""); - } - redraw = true; - break; - - case wimp_KEY_LEFT: - c_pos = ro_textarea_get_caret((uintptr_t)ta); - if (c_pos > 0) - ro_textarea_set_caret((uintptr_t)ta, c_pos - 1); - break; - case wimp_KEY_RIGHT: - c_pos = ro_textarea_get_caret((uintptr_t)ta); - ro_textarea_set_caret((uintptr_t)ta, c_pos + 1); - break; - case wimp_KEY_UP: - /** \todo Move caret up a line */ - break; - case wimp_KEY_DOWN: - /** \todo Move caret down a line */ - break; - - case wimp_KEY_HOME: - case wimp_KEY_CONTROL | wimp_KEY_LEFT: - /** \todo line start */ - break; - case wimp_KEY_CONTROL | wimp_KEY_RIGHT: - /** \todo line end */ - break; - case wimp_KEY_CONTROL | wimp_KEY_UP: - ro_textarea_set_caret((uintptr_t)ta, 0); - break; - case wimp_KEY_CONTROL | wimp_KEY_DOWN: - ro_textarea_set_caret((uintptr_t)ta, - utf8_length(ta->text)); - break; - - case wimp_KEY_COPY: - if (os_version < RISCOS5) { - c_pos = ro_textarea_get_caret((uintptr_t)ta); - ro_textarea_replace_text((uintptr_t)ta, c_pos, - c_pos + 1, ""); - } else { - /** \todo line end */ - } - break; - - /** pass on RETURN and ESCAPE to the parent icon */ - case wimp_KEY_RETURN: - if (ta->flags & TEXTAREA_MULTILINE) { - /* Insert newline */ - c_pos = ro_textarea_get_caret((uintptr_t)ta); - ro_textarea_insert_text((uintptr_t)ta, c_pos, - "\n"); - ro_textarea_set_caret((uintptr_t)ta, ++c_pos); - - redraw = true; - - break; - } - /* fall through */ - case wimp_KEY_ESCAPE: - keypress = *key; - keypress.w = ta->parent; - keypress.i = ta->icon; - keypress.index = 0; /* undefined if not in an icon */ - error = xwimp_send_message_to_window(wimp_KEY_PRESSED, - (wimp_message*)&keypress, ta->parent, - ta->icon, 0); - if (error) { - LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess); - } - break; - } - } - - if (redraw) { - wimp_draw update; - - 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); - ro_textarea_redraw_internal(&update, true); - } - - return true; -} - -/** - * Handle WIMP redraw requests for text areas - * - * \param redraw Redraw request block - */ -void ro_textarea_redraw(wimp_draw *redraw) -{ - ro_textarea_redraw_internal(redraw, false); -} - -/** - * Internal textarea redraw routine - * - * \param redraw Redraw/update request block - * \param update True if update, false if full redraw - */ -void ro_textarea_redraw_internal(wimp_draw *redraw, bool update) -{ - struct text_area *ta; - int line; - osbool more; - rufl_code code; - os_error *error; - - ta = (struct text_area *)ro_gui_wimp_event_get_user_data(redraw->w); - - if (update) - error = xwimp_update_window(redraw, &more); - else - error = xwimp_redraw_window(redraw, &more); - if (error) { - LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess); - return; - } - - while (more) { - int line0, line1; - int clip_y0, clip_y1; - clip_y0 = (redraw->box.y1-redraw->yscroll) - redraw->clip.y1; - clip_y1 = (redraw->box.y1-redraw->yscroll) - redraw->clip.y0; - - error = xcolourtrans_set_gcol( - (ta->flags & TEXTAREA_READONLY) ? 0xD9D9D900 - : 0xFFFFFF00, - colourtrans_SET_BG_GCOL | colourtrans_USE_ECFS_GCOL, - os_ACTION_OVERWRITE, 0, 0); - if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); - return; - } - - error = xos_clg(); - if (error) { - LOG("xos_clg: 0x%x: %s", error->errnum, error->errmess); - return; - } - - if (!ta->lines) - /* Nothing to redraw */ - return; - - line0 = clip_y0 / ta->line_height - 1; - line1 = clip_y1 / ta->line_height + 1; - - if (line0 < 0) - line0 = 0; - if (line1 < 0) - line1 = 0; - if (ta->line_count - 1 < (unsigned)line0) - line0 = ta->line_count - 1; - if (ta->line_count - 1 < (unsigned)line1) - line1 = ta->line_count - 1; - if (line1 < line0) - line1 = line0; - - for (line = line0; line <= line1; line++) { - if (ta->lines[line].b_length == 0) - continue; - - error = xcolourtrans_set_font_colours(font_CURRENT, - (ta->flags & TEXTAREA_READONLY) ? - 0xD9D9D900 : 0xFFFFFF00, - 0x00000000, 14, 0, 0, 0); - if (error) { - LOG("xcolourtrans_set_font_colours: 0x%x: %s", error->errnum, error->errmess); - return; - } - - code = rufl_paint(ta->font_family, ta->font_style, - ta->font_size, - ta->text + ta->lines[line].b_start, - ta->lines[line].b_length, - redraw->box.x0 - redraw->xscroll + MARGIN_LEFT, - redraw->box.y1 - redraw->yscroll - - ((line + 1) * - ta->line_height - ta->line_spacing), - rufl_BLEND_FONT); - if (code != rufl_OK) { - if (code == rufl_FONT_MANAGER_ERROR) - LOG("rufl_paint: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess); - else - LOG("rufl_paint: 0x%x", code); - } - } - - error = xwimp_get_rectangle(redraw, &more); - if (error) { - LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess); - return; - } - } -} - -/** - * Handle a WIMP open window request - * - * \param open OpenWindow block - */ -void ro_textarea_open(wimp_open *open) -{ - os_error *error; - - error = xwimp_open_window(open); - if (error) { - LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); - return; - } -} |