netsurf/riscos/query.c

325 lines
8.0 KiB
C

/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
*/
#include <stdlib.h>
#include <string.h>
#include "netsurf/riscos/dialog.h"
#include "netsurf/riscos/query.h"
#include "netsurf/riscos/wimp.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/messages.h"
#include "netsurf/utils/utils.h"
/** Data for a query window */
struct gui_query_window
{
struct gui_query_window *prev; /** Previous query in list */
struct gui_query_window *next; /** Next query in list */
query_id id; /** unique ID number for this query */
wimp_w window; /** RISC OS window handle */
const query_callback *cb; /** Table of callback functions */
void *pw; /** Handle passed to callback functions */
bool default_confirm; /** Default action is to confirm */
};
/** Next unallocated query id */
static query_id next_id = (query_id)1;
/** List of all query windows. */
static struct gui_query_window *gui_query_window_list = 0;
/** Template for a query window. */
static struct wimp_window *query_template;
/** Widths of Yes and No buttons */
static int query_yes_width = 0;
static int query_no_width = 0;
static void ro_gui_query_window_destroy(struct gui_query_window *qw);
static struct gui_query_window *ro_gui_query_window_lookup_id(query_id id);
void ro_gui_query_init(void)
{
query_template = ro_gui_dialog_load_template("query");
}
/**
* Lookup a query window using its RISC OS window handle
*
* \param w RISC OS window handle
* \return pointer to query window or NULL
*/
struct gui_query_window *ro_gui_query_window_lookup(wimp_w w)
{
struct gui_query_window *qw = gui_query_window_list;
while (qw && qw->window != w)
qw = qw->next;
return qw;
}
/**
* Lookup a query window using its ID number
*
* \param id id to search for
* \return pointer to query window or NULL
*/
struct gui_query_window *ro_gui_query_window_lookup_id(query_id id)
{
struct gui_query_window *qw = gui_query_window_list;
while (qw && qw->id != id)
qw = qw->next;
return qw;
}
/**
* Display a query to the user, requesting a response.
*
* \param query message token of query
* \param detail parameter used in expanding tokenised message
* \param cb table of callback functions to be called when user responds
* \param pw handle to be passed to callback functions
* \param yes text to use for 'Yes' button' (or NULL for default)
* \param no text to use for 'No' button (or NULL for default)
* \return id number of the query (or QUERY_INVALID if it failed)
*/
query_id query_user(const char *query, const char *detail,
const query_callback *cb, void *pw,
const char *yes, const char *no)
{
struct gui_query_window *qw;
char query_buffer[300];
os_error *error;
wimp_icon *icn;
int width;
int len;
int x;
qw = malloc(sizeof(struct gui_query_window));
if (!qw) {
warn_user("NoMemory", NULL);
return QUERY_INVALID;
}
qw->cb = cb;
qw->pw = pw;
qw->id = next_id++;
qw->default_confirm = false;
if (next_id == QUERY_INVALID)
next_id++;
if (!yes) yes = messages_get("Yes");
if (!no) no = messages_get("No");
/* set the text of the 'No' button and size accordingly */
icn = &query_template->icons[ICON_QUERY_NO];
len = strnlen(no, icn->data.indirected_text.size - 1);
memcpy(icn->data.indirected_text.text, no, len);
icn->data.indirected_text.text[len] = '\0';
error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width);
if (error) {
LOG(("xwimptextop_string_width: 0x%x:%s",
error->errnum, error->errmess));
width = len * 16;
}
if (!query_no_width) query_no_width = icn->extent.x1 - icn->extent.x0;
if (width < query_no_width)
width = query_no_width;
else
width += 44;
icn->extent.x0 = x = icn->extent.x1 - width;
/* set the text of the 'Yes' button and size accordingly */
icn = &query_template->icons[ICON_QUERY_YES];
len = strnlen(yes, icn->data.indirected_text.size - 1);
memcpy(icn->data.indirected_text.text, yes, len);
icn->data.indirected_text.text[len] = '\0';
if (!query_yes_width) query_yes_width = icn->extent.x1 - icn->extent.x0;
icn->extent.x1 = x - 16;
error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width);
if (error) {
LOG(("xwimptextop_string_width: 0x%x:%s",
error->errnum, error->errmess));
width = len * 16;
}
if (width < query_yes_width)
width = query_yes_width;
else
width += 28;
icn->extent.x0 = icn->extent.x1 - width;
error = xwimp_create_window(query_template, &qw->window);
if (error) {
warn_user("WimpError", error->errmess);
free(qw);
return QUERY_INVALID;
}
snprintf(query_buffer, sizeof query_buffer, "%s %s",
messages_get(query), detail ? detail : "");
query_buffer[sizeof query_buffer - 1] = 0;
ro_gui_set_icon_string(qw->window, ICON_QUERY_MESSAGE, query_buffer);
xwimp_set_icon_state(qw->window, ICON_QUERY_HELP,
wimp_ICON_DELETED, wimp_ICON_DELETED);
ro_gui_dialog_open(qw->window);
error = xwimp_set_caret_position(qw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
if (error) {
LOG(("xwimp_get_caret_position: 0x%x : %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
/* put this query window at the head of our list */
if (gui_query_window_list)
gui_query_window_list->prev = qw;
qw->prev = NULL;
qw->next = gui_query_window_list;
gui_query_window_list = qw;
return qw->id;
}
/**
* Close and destroy a query window, releasing all resources
*
* \param qw query window
*/
void ro_gui_query_window_destroy(struct gui_query_window *qw)
{
os_error *error = xwimp_delete_window(qw->window);
if (error) {
LOG(("xwimp_delete_window: 0x%x:%s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
/* remove from linked-list of query windows and release memory */
if (qw->prev)
qw->prev->next = qw->next;
else
gui_query_window_list = qw->next;
if (qw->next)
qw->next->prev = qw->prev;
free(qw);
}
/**
* Close a query window without waiting for a response from the user.
* (should normally only be called if the user has responded in some other
* way of which the query window in unaware.)
*
* \param id id of query window to close
*/
void query_close(query_id id)
{
struct gui_query_window *qw = ro_gui_query_window_lookup_id(id);
if (qw) ro_gui_query_window_destroy(qw);
}
void ro_gui_query_window_bring_to_front(query_id id)
{
struct gui_query_window *qw = ro_gui_query_window_lookup_id(id);
if (qw) {
os_error *error;
ro_gui_dialog_open(qw->window);
error = xwimp_set_caret_position(qw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
if (error) {
LOG(("xwimp_get_caret_position: 0x%x : %s",
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
}
}
}
/**
* Handle mouse clicks in a query window.
*
* \param qw query window
* \param key key press info from the Wimp
*/
void ro_gui_query_window_click(struct gui_query_window *qw, wimp_pointer *pointer)
{
const query_callback *cb = qw->cb;
switch (pointer->i) {
case ICON_QUERY_YES:
cb->confirm(qw->id, QUERY_YES, qw->pw);
ro_gui_query_window_destroy(qw);
break;
case ICON_QUERY_NO:
cb->cancel(qw->id, QUERY_NO, qw->pw);
ro_gui_query_window_destroy(qw);
break;
case ICON_QUERY_HELP:
/* \todo */
break;
}
}
/**
* Handle keypresses in a query window.
*
* \param qw query window
* \param pointer mouse pointer state from Wimp.
* \return true iff the key press is the key press has been handled
*/
bool ro_gui_query_window_keypress(struct gui_query_window *qw, wimp_key *key)
{
const query_callback *cb = qw->cb;
switch (key->c) {
case wimp_KEY_ESCAPE:
cb->escape(qw->id, QUERY_ESCAPE, qw->pw);
ro_gui_query_window_destroy(qw);
return true;
case wimp_KEY_RETURN:
if (qw->default_confirm)
cb->confirm(qw->id, QUERY_YES, qw->pw);
else
cb->cancel(qw->id, QUERY_NO, qw->pw);
ro_gui_query_window_destroy(qw);
return true;
}
return true;
}