[PATCH] SELECT form controls
This patch adds (partial) support for SELECT controls in forms. Please note: * SELECTED and DISABLED are supported. * If no item is selected in the HTML source then the first item is selected by default. This means the code must delay adding any items until the SELECT is closed, since the DW API forces us to choose whether to select an item when creating it and won't let us change that later. * MULTI and SIZE are not supported: we render all SELECT controls as option menus that allow only one choice. I believe more work needs to be done on the DW ListResource before we can support multiple selections. * I added IN_OPTION to the HTML parsing flags. The code is also more careful than before to set/unset IN_FORM, IN_TEXTAREA, IN_SELECT and IN_OPTION. This may be a little redundant but I wanted to be sure that HTML tag soup can't make the flags inconsistent. I doubt the overhead of the extra bit-flipping is significant. Regards, Jeremy Henty
I get some errors like html.cc:3832: error: jump to case label html.cc:3808: error: crosses initialization of 'int size' html.cc:3806: error: crosses initialization of 'dw::core::ui::SelectionResource* sel_res The compiler is happy after I separate it out as SelectionResource *sel_res; int size; sel_res =(SelectionResource*)((Embed*)input->widget)->getResource(); size = input->select->options->size (); however. Weird. I have no idea why that matters to the compiler. (g++ -v: gcc version 4.1.2) SELECT is a milestone because it means I will no longer have any reason to run 0.8.x! ---- Free trivia for anybody reading to the bottom of this msg: I finally noticed that file: directory listings have a '%' toggle that you can click to switch from the default format to a good format.
On Sun, Dec 30, 2007 at 05:05:23PM +0000, place wrote:
I get some errors like
html.cc:3832: error: jump to case label html.cc:3808: error: crosses initialization of 'int size' html.cc:3806: error: crosses initialization of 'dw::core::ui::SelectionResource* sel_res
The compiler is happy after I separate it out as
SelectionResource *sel_res; int size; sel_res =(SelectionResource*)((Embed*)input->widget)->getResource(); size = input->select->options->size ();
Thanks for the report. I've attached an updated patch as you suggest. There's no problem with the original code under gcc 3.4.3 . I guess it's one of the things gcc 4.x is more picky about.
I have no idea why that matters to the compiler.
Perhaps the problem is that the variables sel_res and size remain in scope in subsequent cases of the switch, yet if those cases are executed then the variables won't be initialised. What happens if you confine the scope of those variables by putting the body of the case clause inside {...} ? Does the compiler still complain?
SELECT is a milestone because it means I will no longer have any reason to run 0.8.x!
Same here, that's why I was keen to implement it. Regards, Jeremy Henty
Jeremy wrote:
I guess it's one of the things gcc 4.x is more picky about.
Yeah, I had to go to 4.x after Jorge reported a bunch of sign warnings in my decoding stuff...
Perhaps the problem is that the variables sel_res and size remain in scope in subsequent cases of the switch, yet if those cases are executed then the variables won't be initialised.
If it can tell in the new version that the variables aren't being used in subsequent cases, then I'd expect it to be able to able to tell in the old version.
What happens if you confine the scope of those variables by putting the body of the case clause inside {...} ? Does the compiler still complain?
That works.
On Sun, Dec 30, 2007 at 08:33:44PM +0000, place wrote:
Jeremy wrote:
What happens if you confine the scope of those variables by putting the body of the case clause inside {...} ? Does the compiler still complain?
That works.
OK, that confirms it's an issue with the scope of those variables, though like you I'm surprised that the compiler complains when you don't even use them. Regards, Jeremy Henty
Hi Jeremy, works like a charm so far. Now one can edit bookmarks again! Thanks for your work on this, Johannes On Sun, Dec 30, 2007 at 07:52:35AM +0000, Jeremy Henty wrote:
This patch adds (partial) support for SELECT controls in forms. Please note:
* SELECTED and DISABLED are supported.
* If no item is selected in the HTML source then the first item is selected by default. This means the code must delay adding any items until the SELECT is closed, since the DW API forces us to choose whether to select an item when creating it and won't let us change that later.
* MULTI and SIZE are not supported: we render all SELECT controls as option menus that allow only one choice. I believe more work needs to be done on the DW ListResource before we can support multiple selections.
* I added IN_OPTION to the HTML parsing flags. The code is also more careful than before to set/unset IN_FORM, IN_TEXTAREA, IN_SELECT and IN_OPTION. This may be a little redundant but I wanted to be sure that HTML tag soup can't make the flags inconsistent. I doubt the overhead of the extra bit-flipping is significant.
Regards,
Jeremy Henty
diff -pru -- dillo2-ref/src/html.cc dillo2-cur/src/html.cc --- dillo2-ref/src/html.cc 2007-12-28 21:02:20.000000000 +0000 +++ dillo2-cur/src/html.cc 2007-12-30 06:13:14.000000000 +0000 @@ -90,9 +90,9 @@ typedef struct _DilloLinkImage DilloLi typedef struct _DilloHtmlClass DilloHtmlClass; typedef struct _DilloHtmlState DilloHtmlState; typedef struct _DilloHtmlForm DilloHtmlForm; -typedef struct _DilloHtmlOption DilloHtmlOption; -typedef struct _DilloHtmlSelect DilloHtmlSelect; typedef struct _DilloHtmlInput DilloHtmlInput; +typedef struct _DilloHtmlSelect DilloHtmlSelect; +typedef struct _DilloHtmlOption DilloHtmlOption;
typedef enum { DT_NONE, @@ -175,10 +175,11 @@ typedef enum { IN_BODY = 1 << 2, IN_FORM = 1 << 3, IN_SELECT = 1 << 4, - IN_TEXTAREA = 1 << 5, - IN_MAP = 1 << 6, - IN_PRE = 1 << 7, - IN_BUTTON = 1 << 8 + IN_OPTION = 1 << 5, + IN_TEXTAREA = 1 << 6, + IN_MAP = 1 << 7, + IN_PRE = 1 << 8, + IN_BUTTON = 1 << 9, } DilloHtmlProcessingState;
/*----------------------------------------------------------------------------- @@ -231,18 +232,12 @@ struct _DilloHtmlForm { };
struct _DilloHtmlOption { - //GtkWidget *menuitem; - char *value; - bool_t init_val; + char *value, *content; + bool selected, enabled; };
struct _DilloHtmlSelect { - //GtkWidget *menu; - int size; - - DilloHtmlOption *options; - int num_options; - int num_options_max; + misc::SimpleVector<DilloHtmlOption *> *options; };
struct _DilloHtmlInput { @@ -858,31 +853,33 @@ void DilloHtml::initDw() */ DilloHtml::~DilloHtml() { - int i, j, k; - DilloHtmlForm *form; - DilloHtmlInput *input_j; - _MSG("::~DilloHtml(this=%p)\n", this);
a_Bw_remove_doc(bw, this);
a_Url_free(base_url);
- for (i = 0; i < forms->size(); i++) { - form = forms->getRef(i); + for (int i = 0; i < forms->size(); i++) { + DilloHtmlForm *form = forms->getRef(i); a_Url_free(form->action); - for (j = 0; j < form->inputs->size(); j++) { - input_j = form->inputs->getRef(j); - dFree(input_j->name); - dFree(input_j->init_str); - - if (input_j->type == DILLO_HTML_INPUT_SELECT || - input_j->type == DILLO_HTML_INPUT_SEL_LIST) { - for (k = 0; k < input_j->select->num_options; k++) { - dFree(input_j->select->options[k].value); + for (int j = 0; j < form->inputs->size(); j++) { + DilloHtmlInput *input = form->inputs->getRef(j); + dFree(input->name); + dFree(input->init_str); + + if (input->type == DILLO_HTML_INPUT_SELECT || + input->type == DILLO_HTML_INPUT_SEL_LIST) { + + int size = input->select->options->size (); + for (int k = 0; k < size; k++) { + DilloHtmlOption *option = + input->select->options->get (k); + dFree(option->value); + dFree(option->content); + delete(option); } - dFree(input_j->select->options); - dFree(input_j->select); + delete(input->select->options); + delete(input->select); } } delete(form->inputs); @@ -890,12 +887,12 @@ DilloHtml::~DilloHtml() } delete(forms);
- for (i = 0; i < links->size(); i++) + for (int i = 0; i < links->size(); i++) if (links->get(i)) a_Url_free(links->get(i)); delete (links);
- for (i = 0; i < images->size(); i++) { + for (int i = 0; i < images->size(); i++) { DilloLinkImage *li = images->get(i); a_Url_free(li->url); if (li->image) @@ -3435,6 +3432,9 @@ static void Html_tag_open_form(DilloHtml return; } html->InFlags |= IN_FORM; + html->InFlags &= ~IN_SELECT; + html->InFlags &= ~IN_OPTION; + html->InFlags &= ~IN_TEXTAREA;
method = DILLO_HTML_METHOD_GET; if ((attrbuf = Html_get_attr(html, tag, tagsize, "method"))) { @@ -3491,9 +3491,12 @@ static void Html_tag_close_form(DilloHtm // } // } } + html->InFlags &= ~IN_FORM; html->InFlags &= ~IN_SELECT; + html->InFlags &= ~IN_OPTION; html->InFlags &= ~IN_TEXTAREA; + Html_pop_tag(html, TagIdx); }
@@ -3601,20 +3604,20 @@ static void Html_reset_input(DilloHtmlIn /* this is in reverse order so that, in case more than one was * selected, we get the last one, which is consistent with handling * of multiple selected options in the layout code. */ - for (i = input->select->num_options - 1; i >= 0; i--) { - if (input->select->options[i].init_val) { +// for (i = input->select->num_options - 1; i >= 0; i--) { +// if (input->select->options[i].init_val) { // gtk_menu_item_activate(GTK_MENU_ITEM // (input->select->options[i].menuitem)); // Html_select_set_history(input); - break; - } - } +// break; +// } +// } } break; case DILLO_HTML_INPUT_SEL_LIST: if (!input->select) break; - for (i = 0; i < input->select->num_options; i++) { +// for (i = 0; i < input->select->num_options; i++) { // if (input->select->options[i].init_val) { // if (input->select->options[i].menuitem->state == GTK_STATE_NORMAL) // gtk_list_select_child(GTK_LIST(input->select->menu), @@ -3624,7 +3627,7 @@ static void Html_reset_input(DilloHtmlIn // gtk_list_unselect_child(GTK_LIST(input->select->menu), // input->select->options[i].menuitem); // } - } +// } break; case DILLO_HTML_INPUT_TEXTAREA: if (input->init_str != NULL) { @@ -3805,25 +3808,19 @@ static void Html_submit_form2(DilloHtml case DILLO_HTML_INPUT_HIDDEN: Html_append_input(DataStr, input->name, input->init_str); break; -// case DILLO_HTML_INPUT_SELECT: -// for (i = 0; i < input->select->num_options; i++) { -// if (GTK_CHECK_MENU_ITEM(input->select->options[i].menuitem)-> -// active) { -// Html_append_input(DataStr, input->name, -// input->select->options[i].value); -// break; -// } -// } -// break; -// case DILLO_HTML_INPUT_SEL_LIST: -// for (i = 0; i < input->select->num_options; i++) { -// if (input->select->options[i].menuitem->state == -// GTK_STATE_SELECTED) { -// Html_append_input(DataStr, input->name, -// input->select->options[i].value); -// } -// } -// break; + case DILLO_HTML_INPUT_SELECT: + case DILLO_HTML_INPUT_SEL_LIST: + SelectionResource *sel_res = + (SelectionResource*)((Embed*)input->widget)->getResource(); + int size = input->select->options->size (); + for (int i = 0; i < size; i++) { + if (sel_res->isSelected(i)) { + DilloHtmlOption *option = + input->select->options->get (i); + Html_append_input(DataStr, input->name, option->value); + } + } + break; // case DILLO_HTML_INPUT_INDEX: // Html_urlencode_append(DataStr, // gtk_entry_get_text(GTK_ENTRY(input->widget))); @@ -4212,7 +4209,8 @@ static void Html_tag_close_textarea(Dill Widget *widget; int i;
- if (html->InFlags & IN_FORM && html->InFlags & IN_TEXTAREA) { + if (html->InFlags & IN_FORM && + html->InFlags & IN_TEXTAREA) { /* Remove the line ending that follows the opening tag */ if (html->Stash->str[0] == '\r') dStr_erase(html->Stash, 0, 1); @@ -4339,28 +4337,29 @@ static void Html_tag_open_textarea(Dillo /* The select tag is quite tricky, because of gorpy html syntax. */ static void Html_tag_open_select(DilloHtml *html, const char *tag, int tagsize) { -// DilloHtmlForm *form; -// DilloHtmlSelect *Select; -// GtkWidget *widget, *menu; -// char *name; // const char *attrbuf; // int size, type, multi; -// -// if (!(html->InFlags & IN_FORM)) { -// MSG_HTML("<select> outside <form>\n"); -// return; -// } -// if (html->InFlags & IN_SELECT) { -// MSG_HTML("nested <select>\n"); -// return; -// } -// html->InFlags |= IN_SELECT; -// -// -// form = forms->getRef (forms->size() - 1); -// -// name = Html_get_attr_wdef(html, tag, tagsize, "name", NULL); -// + + if (!(html->InFlags & IN_FORM)) { + MSG_HTML("<select> outside <form>\n"); + return; + } + if (html->InFlags & IN_SELECT) { + MSG_HTML("nested <select>\n"); + return; + } + html->InFlags |= IN_SELECT; + html->InFlags &= ~IN_OPTION; + + DilloHtmlForm *form = html->forms->getRef (html->forms->size() - 1); + char *name = Html_get_attr_wdef(html, tag, tagsize, "name", NULL); + OptionMenuResource *res = + HT2LT(html)->getResourceFactory()->createOptionMenuResource (); + Widget *widget; + Embed *embed; + widget = embed = new Embed(res); + DW2TB(html->dw)->addWidget (embed, S_TOP(html)->style); + // size = 0; // if ((attrbuf = Html_get_attr(html, tag, tagsize, "size"))) // size = strtol(attrbuf, NULL, 10); @@ -4380,17 +4379,13 @@ static void Html_tag_open_select(DilloHt // gtk_list_set_selection_mode(GTK_LIST(menu), GTK_SELECTION_MULTIPLE); // type = DILLO_HTML_INPUT_SEL_LIST; // } -// -// Select = dNew(DilloHtmlSelect, 1); -// Select->menu = menu; -// Select->size = size; -// Select->num_options = 0; -// Select->num_options_max = 8; -// Select->options = dNew(DilloHtmlOption, Select->num_options_max); -// -// Html_add_input(form, type, widget, name, NULL, Select, FALSE); -// Html_stash_init(html); -// dFree(name); + + DilloHtmlSelect *select = new DilloHtmlSelect; + select->options = new misc::SimpleVector<DilloHtmlOption *> (4); + Html_add_input(form, DILLO_HTML_INPUT_SELECT, widget, embed, name, + NULL, select, false); + Html_stash_init(html); + dFree(name); }
/* @@ -4398,47 +4393,19 @@ static void Html_tag_open_select(DilloHt */ static void Html_option_finish(DilloHtml *html) { -// DilloHtmlForm *form; -// DilloHtmlInput *input; -// GtkWidget *menuitem; -// GSList *group; -// DilloHtmlSelect *select; -// -// if (!(html->InFlags & IN_FORM)) -// return; -// -// form = html->forms->getRef (html->forms->size() - 1); -// input = form->inputs->getRef (form->inputs->size() - 1); -// if (input->select->num_options <= 0) -// return; -// -// select = input->select; -// if (input->type == DILLO_HTML_INPUT_SELECT ) { -// if (select->num_options == 1) -// group = NULL; -// else -// group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM -// (select->options[0].menuitem)); -// menuitem = gtk_radio_menu_item_new_with_label(group, html->Stash->str); -// select->options[select->num_options - 1].menuitem = menuitem; -// if (select->options[select->num_options - 1].value == NULL) -// select->options[select->num_options - 1].value = -// dStrdup(html->Stash->str); -// gtk_menu_append(GTK_MENU(select->menu), menuitem); -// if (select->options[select->num_options - 1].init_val) -// gtk_menu_item_activate(GTK_MENU_ITEM(menuitem)); -// gtk_widget_show(menuitem); -// } else if (input->type == DILLO_HTML_INPUT_SEL_LIST) { -// menuitem = gtk_list_item_new_with_label(html->Stash->str); -// select->options[select->num_options - 1].menuitem = menuitem; -// if (select->options[select->num_options - 1].value == NULL) -// select->options[select->num_options - 1].value = -// dStrdup(html->Stash->str); -// gtk_container_add(GTK_CONTAINER(select->menu), menuitem); -// if (select->options[select->num_options - 1].init_val) -// gtk_list_select_child(GTK_LIST(select->menu), menuitem); -// gtk_widget_show(menuitem); -// } + DilloHtmlForm *form = + html->forms->getRef (html->forms->size() - 1); + DilloHtmlInput *input = + form->inputs->getRef (form->inputs->size() - 1); + if (input->type == DILLO_HTML_INPUT_SELECT || + input->type == DILLO_HTML_INPUT_SEL_LIST) { + DilloHtmlSelect *select = + input->select; + DilloHtmlOption *option = + select->options->get (select->options->size() - 1); + option->content = + Html_parse_entities(html, html->Stash->str, html->Stash->len); + } }
/* @@ -4446,28 +4413,36 @@ static void Html_option_finish(DilloHtml */ static void Html_tag_open_option(DilloHtml *html, const char *tag, int tagsize) { -// DilloHtmlForm *form; -// DilloHtmlInput *input; -// int no; -// -// if (!(html->InFlags & IN_SELECT)) -// return; -// -// form = forms->getRef (forms->size() - 1); -// input = form->inputs->getRef (form->inputs->size() - 1); -// if (input->type == DILLO_HTML_INPUT_SELECT || -// input->type == DILLO_HTML_INPUT_SEL_LIST) { -// Html_option_finish(html); -// no = input->select->num_options; -// a_List_add(input->select->options, no, input->select->num_options_max); -// input->select->options[no].menuitem = NULL; -// input->select->options[no].value = Html_get_attr_wdef(html, tag, tagsize, -// "value", NULL); -// input->select->options[no].init_val = -// (Html_get_attr(html, tag, tagsize, "selected") != NULL); -// input->select->num_options++; -// } -// Html_stash_init(html); + if (!(html->InFlags & IN_FORM && + html->InFlags & IN_SELECT )) + return; + if (html->InFlags & IN_OPTION) + Html_option_finish(html); + html->InFlags |= IN_OPTION; + + DilloHtmlForm *form = + html->forms->getRef (html->forms->size() - 1); + DilloHtmlInput *input = + form->inputs->getRef (form->inputs->size() - 1); + + if (input->type == DILLO_HTML_INPUT_SELECT || + input->type == DILLO_HTML_INPUT_SEL_LIST) { + + DilloHtmlOption *option = new DilloHtmlOption; + option->value = + Html_get_attr_wdef(html, tag, tagsize, "value", NULL); + option->content = NULL; + option->selected = + (Html_get_attr(html, tag, tagsize, "selected") != NULL); + option->enabled = + (Html_get_attr(html, tag, tagsize, "disabled") == NULL); + + int size = input->select->options->size (); + input->select->options->increase (); + input->select->options->set (size, option); + } + + Html_stash_init(html); }
/* @@ -4475,71 +4450,49 @@ static void Html_tag_open_option(DilloHt */ static void Html_tag_close_select(DilloHtml *html, int TagIdx) { -// // AL -// DilloHtmlForm *form; -// DilloHtmlInput *input; -// GtkWidget *scrolledwindow; -// Widget *embed_gtk; -// GtkRequisition req; -// int height; -// -// if (html->InFlags & IN_SELECT) { -// html->InFlags &= ~IN_SELECT; -// -// form = forms->getRef (forms->size() - 1); -// input = form->inputs->getRef (form->inputs->size() - 1); -// if (input->type == DILLO_HTML_INPUT_SELECT) { -// Html_option_finish(html); -// -// gtk_option_menu_set_menu(GTK_OPTION_MENU(input->widget), -// input->select->menu); -// Html_select_set_history(input); -// -// // gtk_option_menu_set_history(GTK_OPTION_MENU(input->widget), 1); -// -// gtk_widget_show(input->widget); -// -// embed_gtk = a_Dw_embed_gtk_new (); -// a_Dw_embed_gtk_add_gtk (DW_EMBED_GTK (embed_gtk), input->widget); -// DW2TB(html->dw)->addWidget (embed_gtk, -// S_TOP(html)->style); -// } else if (input->type == DILLO_HTML_INPUT_SEL_LIST) { -// Html_option_finish(html); -// -// if (input->select->size < input->select->num_options) { -// scrolledwindow = gtk_scrolled_window_new(NULL, NULL); -// gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), -// GTK_POLICY_NEVER, -// GTK_POLICY_AUTOMATIC); -// gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW -// (scrolledwindow), -// input->widget); -// -// gtk_container_set_focus_vadjustment -// (GTK_CONTAINER (input->widget), -// gtk_scrolled_window_get_vadjustment -// (GTK_SCROLLED_WINDOW(scrolledwindow))); -// -// /* Calculate the height of the scrolled window */ -// gtk_widget_size_request(input->select->options[0].menuitem, &req); -// height = input->select->size * req.height + -// 2 * scrolledwindow->style->klass->ythickness; -// gtk_widget_set_usize(scrolledwindow, -1, height); -// -// gtk_widget_show(input->widget); -// input->widget = scrolledwindow; -// } -// gtk_widget_show(input->widget); -// -// /* note: In this next call, scrolledwindows get a warning from -// * gdkwindow.c:422. I'm not really going to sweat it now - the -// * embedded widget stuff is going to get massively redone anyway. */ -// embed_gtk = a_Dw_embed_gtk_new (); -// a_Dw_embed_gtk_add_gtk (DW_EMBED_GTK (embed_gtk), input->widget); -// DW2TB(html->dw)->addWidget (embed_gtk, -// S_TOP(html)->style); -// } -// } + if (html->InFlags & IN_FORM && + html->InFlags & IN_SELECT) { + if (html->InFlags & IN_OPTION) + Html_option_finish(html); + html->InFlags &= ~IN_SELECT; + html->InFlags &= ~IN_OPTION; + + DilloHtmlForm *form = + html->forms->getRef (html->forms->size() - 1); + DilloHtmlInput *input = + form->inputs->getRef (form->inputs->size() - 1); + SelectionResource *res = + (SelectionResource*)((Embed*)input->widget)->getResource(); + + int size = input->select->options->size (); + if (size > 0) { + // is anything selected? + bool some_selected = false; + for (int i = 0; i < size; i++) { + DilloHtmlOption *option = + input->select->options->get (i); + if (option->selected) { + some_selected = true; + break; + } + } + + // select the first if nothing else is selected + // BUG(?): should not do this for MULTI selections + if (! some_selected) + input->select->options->get (0)->selected = true; + + // add the items to the resource + for (int i = 0; i < size; i++) { + DilloHtmlOption *option = + input->select->options->get (i); + bool enabled = option->enabled; + bool selected = option->selected; + res->addItem(option->content,enabled,selected); + } + } + } + Html_pop_tag(html, TagIdx); }
_______________________________________________ Dillo-dev mailing list Dillo-dev@dillo.org http://lists.auriga.wearlab.de/cgi-bin/mailman/listinfo/dillo-dev
On Sun, Dec 30, 2007 at 07:52:35AM +0000, Jeremy Henty wrote:
This patch adds (partial) support for SELECT controls in forms.
Good work Jeremy, committed! I was also eager to have this working. :-)
Please note:
* SELECTED and DISABLED are supported.
* If no item is selected in the HTML source then the first item is selected by default. This means the code must delay adding any items until the SELECT is closed, since the DW API forces us to choose whether to select an item when creating it and won't let us change that later.
* MULTI and SIZE are not supported: we render all SELECT controls as option menus that allow only one choice. I believe more work needs to be done on the DW ListResource before we can support multiple selections.
* I added IN_OPTION to the HTML parsing flags. The code is also more careful than before to set/unset IN_FORM, IN_TEXTAREA, IN_SELECT and IN_OPTION. This may be a little redundant but I wanted to be sure that HTML tag soup can't make the flags inconsistent. I doubt the overhead of the extra bit-flipping is significant.
A more detailed comment probably next year. I just wanted to commit this cookie!. -- Cheers Jorge.-
participants (4)
-
jcid@dillo.org
-
Johannes.Hofmann@gmx.de
-
onepoint@starurchin.org
-
place@gobigwest.com