From 20ea5ea00fce47a834421d87d800226a5b7441cd Mon Sep 17 00:00:00 2001 From: Phil Mellor Date: Mon, 30 Dec 2002 22:56:30 +0000 Subject: [project @ 2002-12-30 22:56:30 by monkeyson] Forms are now interactive - user can manipulate checkbox, radio, text, textarea, select elements. svn path=/import/netsurf/; revision=76 --- render/box.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++++++----- render/box.h | 44 +++++++- render/layout.c | 12 ++- 3 files changed, 344 insertions(+), 27 deletions(-) (limited to 'render') diff --git a/render/box.c b/render/box.c index e6726b02b..65694810b 100644 --- a/render/box.c +++ b/render/box.c @@ -1,5 +1,5 @@ /** - * $Id: box.c,v 1.24 2002/12/30 02:06:03 monkeyson Exp $ + * $Id: box.c,v 1.25 2002/12/30 22:56:30 monkeyson Exp $ */ #include @@ -19,7 +19,7 @@ * internal functions */ -struct box* box_gui_gadget(xmlNode * n, struct css_style* style); +struct box* input(xmlNode * n, struct css_style* style, struct form* current_form); void box_add_child(struct box * parent, struct box * child); struct box * box_create(xmlNode * node, box_type type, struct css_style * style, @@ -30,7 +30,9 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, struct css_selector ** selector, unsigned int depth, struct box * parent, struct box * inline_container, const char *href, struct font_set *fonts, - struct gui_gadget* current_select, struct formoption* current_option); + struct gui_gadget* current_select, struct formoption* current_option, + struct gui_gadget* current_textarea, struct form* current_form, + struct page_elements* elements); struct css_style * box_get_style(struct css_stylesheet * stylesheet, struct css_style * parent_style, xmlNode * n, struct css_selector * selector, unsigned int depth); void box_normalise_block(struct box *block); @@ -129,11 +131,14 @@ void xml_to_box(xmlNode * n, struct css_style * parent_style, struct css_selector ** selector, unsigned int depth, struct box * parent, struct box * inline_container, const char *href, struct font_set *fonts, - struct gui_gadget* current_select, struct formoption* current_option) + struct gui_gadget* current_select, struct formoption* current_option, + struct gui_gadget* current_textarea, struct form* current_form, + struct page_elements* elements) { LOG(("node %p", n)); convert_xml_to_box(n, parent_style, stylesheet, - selector, depth, parent, inline_container, href, fonts, current_select, current_option); + selector, depth, parent, inline_container, href, fonts, current_select, current_option, + current_textarea, current_form, elements); LOG(("normalising")); box_normalise_block(parent->children); } @@ -149,7 +154,9 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, struct css_selector ** selector, unsigned int depth, struct box * parent, struct box * inline_container, const char *href, struct font_set *fonts, - struct gui_gadget* current_select, struct formoption* current_option) + struct gui_gadget* current_select, struct formoption* current_option, + struct gui_gadget* current_textarea, struct form* current_form, + struct page_elements* elements) { struct box * box; struct box * inline_container_c; @@ -184,10 +191,20 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, } } - if (n->type == XML_TEXT_NODE || + if (n->type == XML_ELEMENT_NODE && (strcmp((const char *) n->name, "form") == 0)) + { + struct form* form = box_form(n); + if (form != NULL) + { + current_form = form; + add_form_element(elements, form); + } + } + else if (n->type == XML_TEXT_NODE || (n->type == XML_ELEMENT_NODE && (strcmp((const char *) n->name, "input") == 0)) || (n->type == XML_ELEMENT_NODE && (strcmp((const char *) n->name, "select") == 0)) || (n->type == XML_ELEMENT_NODE && (strcmp((const char *) n->name, "option") == 0)) || + (n->type == XML_ELEMENT_NODE && (strcmp((const char *) n->name, "textarea") == 0)) || (n->type == XML_ELEMENT_NODE && (strcmp((const char *) n->name, "img") == 0)) || (n->type == XML_ELEMENT_NODE && (style->float_ == CSS_FLOAT_LEFT || style->float_ == CSS_FLOAT_RIGHT))) { @@ -199,9 +216,14 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, } if (n->type == XML_TEXT_NODE) { LOG2("TEXT NODE"); - if (current_option != 0) + if (current_textarea != 0) { char* thistext = squash_whitespace(tolat1(n->content)); + textarea_addtext(current_textarea, thistext); + } + else if (current_option != 0) + { + char* thistext = (tolat1(n->content)); LOG2("adding to option"); option_addtext(current_option, thistext); LOG2("freeing thistext"); @@ -224,25 +246,41 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, } } else if (strcmp((const char *) n->name, "img") == 0) { LOG2(("image")); - box = box_image(n, parent_style); + box = box_image(n, parent_style, href); + if (box != NULL) + { + box_add_child(inline_container, box); + add_img_element(elements, box->img); + } + } else if (strcmp((const char *) n->name, "textarea") == 0) { + LOG2(("textarea")); + box = box_textarea(n, parent_style, current_form); if (box != NULL) + { box_add_child(inline_container, box); + current_textarea = box->gadget; + add_gadget_element(elements, box->gadget); + } } else if (strcmp((const char *) n->name, "select") == 0) { LOG2(("select")); - box = box_select(n, parent_style); + box = box_select(n, parent_style, current_form); if (box != NULL) { box_add_child(inline_container, box); current_select = box->gadget; + add_gadget_element(elements, box->gadget); } } else if (strcmp((const char *) n->name, "option") == 0) { LOG2(("option")); current_option = box_option(n, parent_style, current_select); } else if (strcmp((const char *) n->name, "input") == 0) { LOG2(("input")); - box = box_gui_gadget(n, parent_style); + box = box_input(n, parent_style, current_form, elements); if (box != NULL) + { box_add_child(inline_container, box); + add_gadget_element(elements, box->gadget); + } } else { LOG2(("float")); box = box_create(0, BOX_FLOAT_LEFT, 0, href); @@ -264,14 +302,16 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, for (c = n->children; c != 0; c = c->next) inline_container_c = convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, inline_container_c, - href, fonts, current_select, current_option); + href, fonts, current_select, current_option, + current_textarea, current_form, elements); inline_container = 0; break; case CSS_DISPLAY_INLINE: /* inline elements get no box, but their children do */ for (c = n->children; c != 0; c = c->next) inline_container = convert_xml_to_box(c, style, stylesheet, selector, depth + 1, parent, inline_container, - href, fonts, current_select, current_option); + href, fonts, current_select, current_option, + current_textarea, current_form, elements); break; case CSS_DISPLAY_TABLE: box = box_create(n, BOX_TABLE, style, href); @@ -279,7 +319,8 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, for (c = n->children; c != 0; c = c->next) convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, 0, - href, fonts, current_select, current_option); + href, fonts, current_select, current_option, + current_textarea, current_form, elements); inline_container = 0; break; case CSS_DISPLAY_TABLE_ROW_GROUP: @@ -291,7 +332,8 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, for (c = n->children; c != 0; c = c->next) inline_container_c = convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, inline_container_c, - href, fonts, current_select, current_option); + href, fonts, current_select, current_option, + current_textarea, current_form, elements); inline_container = 0; break; case CSS_DISPLAY_TABLE_ROW: @@ -300,7 +342,8 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, for (c = n->children; c != 0; c = c->next) convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, 0, - href, fonts, current_select, current_option); + href, fonts, current_select, current_option, + current_textarea, current_form, elements); inline_container = 0; break; case CSS_DISPLAY_TABLE_CELL: @@ -315,7 +358,8 @@ struct box * convert_xml_to_box(xmlNode * n, struct css_style * parent_style, for (c = n->children; c != 0; c = c->next) inline_container_c = convert_xml_to_box(c, style, stylesheet, selector, depth + 1, box, inline_container_c, - href, fonts, current_select, current_option); + href, fonts, current_select, current_option, + current_textarea, current_form, elements); inline_container = 0; break; default: @@ -735,6 +779,55 @@ void box_normalise_inline_container(struct box *cont) } +void gadget_free(struct gui_gadget* g) +{ + struct formoption* o; + + if (g->name != 0) + xfree(g->name); + + switch (g->type) + { + case GADGET_HIDDEN: + if (g->data.hidden.value != 0) + xfree(g->data.hidden.value); + break; + case GADGET_RADIO: + if (g->data.checkbox.value != 0) + xfree(g->data.radio.value); + break; + case GADGET_CHECKBOX: + if (g->data.checkbox.value != 0) + xfree(g->data.checkbox.value); + break; + case GADGET_TEXTAREA: + if (g->data.textarea.text != 0) + xfree(g->data.textarea.text); + break; + case GADGET_TEXTBOX: + gui_remove_gadget(g); + if (g->data.textbox.text != 0) + xfree(g->data.textbox.text); + break; + case GADGET_ACTIONBUTTON: + if (g->data.actionbutt.label != 0) + xfree(g->data.actionbutt.label); + break; + case GADGET_SELECT: + o = g->data.select.items; + while (o != NULL) + { + if (o->text != 0) + xfree(o->text); + if (o->value != 0) + xfree(o->value); + xfree(o); + o = o->next; + } + break; + } +} + /** * free a box tree recursively */ @@ -754,7 +847,7 @@ void box_free(struct box *box) // free(box->style); if (box->gadget != 0) { - /* gadget_free(box->gadget); */ + gadget_free(box->gadget); free((void*)box->gadget); } @@ -775,12 +868,12 @@ void box_free(struct box *box) } } -struct box* box_image(xmlNode * n, struct css_style* style) +struct box* box_image(xmlNode * n, struct css_style* style, char* href) { struct box* box = 0; char* s; - box = box_create(n, BOX_INLINE, style, NULL); + box = box_create(n, BOX_INLINE, style, href); box->img = xcalloc(1, sizeof(struct img)); box->text = 0; @@ -811,7 +904,47 @@ struct box* box_image(xmlNode * n, struct css_style* style) return box; } -struct box* box_select(xmlNode * n, struct css_style* style) +struct box* box_textarea(xmlNode* n, struct css_style* style, struct form* current_form) +{ + struct box* box = 0; + char* s; + + LOG2("creating box"); + box = box_create(n, BOX_INLINE, style, NULL); + LOG2("creating gadget"); + box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget->type = GADGET_TEXTAREA; + box->gadget->form = current_form; + + box->text = 0; + box->length = 0; + box->font = 0; + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "cols"))) + { + box->gadget->data.textarea.cols = atoi(s); + free(s); + } + else + box->gadget->data.textarea.cols = 40; + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "rows"))) + { + box->gadget->data.textarea.rows = atoi(s); + free(s); + } + else + box->gadget->data.textarea.rows = 16; + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "name"))) + { + box->gadget->name = s; + } + + return box; +} + +struct box* box_select(xmlNode * n, struct css_style* style, struct form* current_form) { struct box* box = 0; char* s; @@ -821,6 +954,7 @@ struct box* box_select(xmlNode * n, struct css_style* style) LOG2("creating gadget"); box->gadget = xcalloc(1, sizeof(struct gui_gadget)); box->gadget->type = GADGET_SELECT; + box->gadget->form = current_form; box->text = 0; box->length = 0; @@ -834,6 +968,14 @@ struct box* box_select(xmlNode * n, struct css_style* style) else box->gadget->data.select.size = 1; + if ((s = (char *) xmlGetProp(n, (xmlChar *) "multiple"))) { + box->gadget->data.select.multiple = 1; + } + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "name"))) { + box->gadget->name = s; + } + box->gadget->data.select.items = NULL; box->gadget->data.select.numitems = 0; /* to do: multiple, name */ @@ -844,7 +986,9 @@ struct box* box_select(xmlNode * n, struct css_style* style) struct formoption* box_option(xmlNode* n, struct css_style* style, struct gui_gadget* current_select) { struct formoption* option; + char* s; assert(current_select != 0); + LOG2("realloc option"); if (current_select->data.select.items == 0) { @@ -862,11 +1006,35 @@ struct formoption* box_option(xmlNode* n, struct css_style* style, struct gui_ga } /* TO DO: set selected / value here */ + if ((s = (char *) xmlGetProp(n, (xmlChar *) "selected"))) { + option->selected = -1; + free(s); + } + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "value"))) { + option->value = s; + } LOG2("returning"); return option; } +void textarea_addtext(struct gui_gadget* textarea, char* text) +{ + assert (textarea != 0); + assert (text != 0); + + if (textarea->data.textarea.text == 0) + { + textarea->data.textarea.text = strdup(text); + } + else + { + textarea->data.textarea.text = xrealloc(textarea->data.textarea.text, strlen(textarea->data.textarea.text) + strlen(text) + 1); + strcat(textarea->data.textarea.text, text); + } +} + void option_addtext(struct formoption* option, char* text) { assert(option != 0); @@ -887,7 +1055,7 @@ void option_addtext(struct formoption* option, char* text) return; } -struct box* box_gui_gadget(xmlNode * n, struct css_style* style) +struct box* box_input(xmlNode * n, struct css_style* style, struct form* current_form, struct page_elements* elements) { struct box* box = 0; char* s; @@ -895,6 +1063,53 @@ struct box* box_gui_gadget(xmlNode * n, struct css_style* style) if ((type = (char *) xmlGetProp(n, (xmlChar *) "type"))) { + if (strcmp(type, "hidden") == 0) + { + struct gui_gadget* g = xcalloc(1, sizeof(struct gui_gadget)); + g->type = GADGET_HIDDEN; + g->form = current_form; + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "value"))) { + g->data.hidden.value = s; + } + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "name"))) { + g->name = s; + } + } + if (strcmp(type, "checkbox") == 0 || strcmp(type, "radio") == 0) + { + box = box_create(n, BOX_INLINE, style, NULL); + box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + if (type[0] == 'c') + box->gadget->type = GADGET_CHECKBOX; + else + box->gadget->type = GADGET_RADIO; + box->gadget->form = current_form; + + box->text = 0; + box->length = 0; + box->font = 0; + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "checked"))) { + if (type[0] == 'c') + box->gadget->data.checkbox.selected = -1; + else + box->gadget->data.radio.selected = -1; + free(s); + } + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "value"))) { + if (type[0] == 'c') + box->gadget->data.checkbox.value = s; + else + box->gadget->data.radio.value = s; + } + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "name"))) { + box->gadget->name = s; + } + } if (strcmp(type, "submit") == 0 || strcmp(type, "reset") == 0) { //style->display = CSS_DISPLAY_BLOCK; @@ -902,6 +1117,7 @@ struct box* box_gui_gadget(xmlNode * n, struct css_style* style) box = box_create(n, BOX_INLINE, style, NULL); box->gadget = xcalloc(1, sizeof(struct gui_gadget)); box->gadget->type = GADGET_ACTIONBUTTON; + box->gadget->form = current_form; box->text = 0; box->length = 0; @@ -915,6 +1131,10 @@ struct box* box_gui_gadget(xmlNode * n, struct css_style* style) box->gadget->data.actionbutt.label = strdup(type); box->gadget->data.actionbutt.label[0] = toupper(type[0]); } + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "name"))) { + box->gadget->name = s; + } } if (strcmp(type, "text") == 0 || strcmp(type, "password") == 0) { @@ -923,12 +1143,13 @@ struct box* box_gui_gadget(xmlNode * n, struct css_style* style) box = box_create(n, BOX_INLINE, style, NULL); box->gadget = xcalloc(1, sizeof(struct gui_gadget)); box->gadget->type = GADGET_TEXTBOX; + box->gadget->form = current_form; box->text = 0; box->length = 0; box->font = 0; - box->gadget->data.textbox.maxlength = 255; + box->gadget->data.textbox.maxlength = 32; if ((s = (char *) xmlGetProp(n, (xmlChar *) "maxlength"))) { box->gadget->data.textbox.maxlength = atoi(s); free(s); @@ -948,8 +1169,56 @@ struct box* box_gui_gadget(xmlNode * n, struct css_style* style) free(s); } + if ((s = (char *) xmlGetProp(n, (xmlChar *) "name"))) { + box->gadget->name = s; + } } free(type); } return box; } + +struct form* box_form(xmlNode* n) +{ + struct form* form; + char* s; + + form = xcalloc(1, sizeof(struct form*)); + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "action"))) { + form->action = s; + } + + if ((s = (char *) xmlGetProp(n, (xmlChar *) "method"))) { + if (strcmp(s, "get") == 0) + form->action = method_GET; + else if (strcmp(s, "post") == 0) + form->action = method_POST; + xfree(s); + } + + return form; +} + +void add_form_element(struct page_elements* pe, struct form* f) +{ + pe->forms = xrealloc(pe->forms, (pe->numForms + 1) * sizeof(struct form*)); + pe->forms[pe->numForms] = f; + pe->numForms++; +} + +void add_gadget_element(struct page_elements* pe, struct gadget* g) +{ + pe->gadgets = xrealloc(pe->gadgets, (pe->numGadgets + 1) * sizeof(struct gui_gadget*)); + pe->gadgets[pe->numGadgets] = g; + pe->numGadgets++; +} + +void add_img_element(struct page_elements* pe, struct img* i) +{ + pe->images = xrealloc(pe->images, (pe->numImages + 1) * sizeof(struct img*)); + pe->images[pe->numImages] = i; + pe->numImages++; +} + + diff --git a/render/box.h b/render/box.h index e978662ad..eb6589118 100644 --- a/render/box.h +++ b/render/box.h @@ -1,5 +1,5 @@ /** - * $Id: box.h,v 1.14 2002/12/30 02:06:03 monkeyson Exp $ + * $Id: box.h,v 1.15 2002/12/30 22:56:30 monkeyson Exp $ */ #ifndef _NETSURF_RENDER_BOX_H_ @@ -35,9 +35,14 @@ struct formoption { }; struct gui_gadget { - enum { GADGET_HIDDEN = 0, GADGET_TEXTBOX, GADGET_RADIO, GADGET_OPTION, + enum { GADGET_HIDDEN = 0, GADGET_TEXTBOX, GADGET_RADIO, GADGET_CHECKBOX, GADGET_SELECT, GADGET_TEXTAREA, GADGET_ACTIONBUTTON } type; + char* name; + struct form* form; union { + struct { + char* value; + } hidden; struct { int maxlength; char* text; @@ -45,6 +50,7 @@ struct gui_gadget { } textbox; struct { char* label; + int pressed; } actionbutt; struct { int numitems; @@ -52,6 +58,19 @@ struct gui_gadget { int size; int multiple; } select; + struct { + int selected; + char* value; + } checkbox; + struct { + int selected; + char* value; + } radio; + struct { + int cols; + int rows; + char* text; + } textarea; } data; }; @@ -85,6 +104,23 @@ struct box { struct img* img; }; +struct form +{ + char* action; /* url */ + enum {method_GET, method_POST} method; +}; + +struct page_elements +{ + struct form** forms; + struct gui_gadget** gadgets; + struct img** images; + int numForms; + int numGadgets; + int numImages; +}; + + #define UNKNOWN_WIDTH ULONG_MAX #define UNKNOWN_MAX_WIDTH ULONG_MAX @@ -96,7 +132,9 @@ void xml_to_box(xmlNode * n, struct css_style * parent_style, struct css_stylesh struct css_selector ** selector, unsigned int depth, struct box * parent, struct box * inline_container, const char *href, struct font_set *fonts, - struct gui_gadget* current_select, struct formoption* current_option); + struct gui_gadget* current_select, struct formoption* current_option, + struct gui_gadget* current_textarea, struct form* current_form, + struct page_elements* elements); void box_dump(struct box * box, unsigned int depth); void box_free(struct box *box); diff --git a/render/layout.c b/render/layout.c index db1432c78..3015d8eeb 100644 --- a/render/layout.c +++ b/render/layout.c @@ -1,5 +1,5 @@ /** - * $Id: layout.c,v 1.29 2002/12/30 02:06:03 monkeyson Exp $ + * $Id: layout.c,v 1.30 2002/12/30 22:56:30 monkeyson Exp $ */ #include @@ -127,6 +127,9 @@ int gadget_width(struct gui_gadget* gadget) /* should use wimp_textop via a gui wraper for these */ switch (gadget->type) { + case GADGET_CHECKBOX: + case GADGET_RADIO: + return 22; case GADGET_TEXTBOX: return gadget->data.textbox.size * 8; case GADGET_ACTIONBUTTON: @@ -141,6 +144,8 @@ int gadget_width(struct gui_gadget* gadget) current = current->next; } return max; + case GADGET_TEXTAREA: + return gadget->data.textarea.cols * 8 + 8; default: assert(0); } @@ -151,12 +156,17 @@ int gadget_height(struct gui_gadget* gadget) { switch (gadget->type) { + case GADGET_CHECKBOX: + case GADGET_RADIO: + return 22; case GADGET_TEXTBOX: return 28; case GADGET_ACTIONBUTTON: return 28; case GADGET_SELECT: return 28; + case GADGET_TEXTAREA: + return gadget->data.textarea.rows * 16 + 8; default: assert(0); } -- cgit v1.2.3