Hi
To better get to know the plotters API I started working on a plotters
based select widget. This patch replaces the pop-up menu with a list
displayed right under the gadget. I am sending it mainly to listen to
what you think of the direction taken so if you have any comments on
the appearance of the gadget or any necessary features, I think it
would be best to know at the initial steps of creating it :). I
consider it a draft and I know the code could be better organised and
less messy so please be understanding at the moment :). My current
todo list contains:
- adding an arrow to the box so that it resembles a combo box
- making the colours customizable
- adding a scroll for really long lists(I'll use the existing one)
- adding a representation of optgroup
- a better handling of mouse events(now it responds only to a click
without the slightest mouse move)
Index: render/form.c
===================================================================
--- render/form.c (wersja 7073)
+++ render/form.c (kopia robocza)
@@ -29,6 +29,10 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
+#include "css/css.h"
+#include "desktop/browser.h"
+#include "desktop/plotters.h"
+#include "desktop/knockout.h"
#include "render/box.h"
#include "render/form.h"
#include "utils/log.h"
@@ -41,6 +45,7 @@
static char *form_acceptable_charset(struct form *form);
static char *form_encode_item(const char *item, const char *charset,
const char *fallback);
+static bool form_redraw_select_menu(struct browser_window *bw, int first_option);
/**
* Create a struct form.
@@ -812,3 +817,151 @@
return ret;
}
+bool form_show_select_menu(struct browser_window *bw,
+ struct form_control *control)
+{
+ if (visible_select_menu)
+ return false;
+
+ visible_select_menu = control;
+ form_redraw_select_menu(bw, 1);
+ return true;
+}
+
+bool form_hide_select_menu(struct browser_window *bw)
+{
+ struct box *box;
+ int x, y, width, height;
+
+ if (!visible_select_menu)
+ return false;
+
+ box = visible_select_menu->box;
+ box_coords(box, &x, &y);
+
+ x -= box->border[3];
+ y += box->height + box->border[2] + box->padding[2] + box->padding[0];
+
+ width = box->width + box->border[1] + box->border[3] + box->padding[1]
+ + box->padding[3];
+ height = visible_select_menu->data.select.height;
+
+ x *= bw->scale;
+ y *= bw->scale;
+ width *= bw->scale;
+ height *= bw->scale;
+
+ browser_window_redraw_rect(bw, x, y, width + 1, height + 1);
+ visible_select_menu = NULL;
+ return true;
+}
+
+bool form_redraw_select_menu(struct browser_window *bw, int first_option)
+{
+ struct box *box;
+ struct form_option *option;
+ bool result, want_knockout;
+ int x, y, width, height, line_height;
+ int x0, y0, x1, y1;
+ int num_lines, i;
+ int colour;
+ float scale = bw->scale;
+
+ if (!visible_select_menu)
+ return false;
+
+ box = visible_select_menu->box;
+ box_coords(box, &x, &y);
+
+ x -= box->border[3];
+ y += box->height + box->border[2] + box->padding[2] + box->padding[0];
+
+ width = box->width + box->border[1] + box->border[3] + box->padding[1]
+ + box->padding[3];
+
+ line_height = css_len2px(&(box->style->font_size.value.length),
+ box->style);
+
+ if (visible_select_menu->data.select.num_items < 20)
+ num_lines = visible_select_menu->data.select.num_items;
+ else
+ num_lines = 20;
+
+ height = visible_select_menu->data.select.height = num_lines
+ * (line_height + 5);
+
+ want_knockout = plot.option_knockout;
+ if (want_knockout)
+ knockout_plot_start(&plot);
+
+ x0 = x * scale;
+ y0 = y * scale;
+ x1 = (x + width) * scale;
+ y1 = (y + height) * scale;
+
+ result = plot.clip(x0, y0, x1, y1);
+ result &= plot.clg(0xDDDDDD);
+
+ option = visible_select_menu->data.select.items;
+ i = 0;
+ while (option && i < num_lines) {
+
+
+ y0 = (y + i * (line_height + 5)) * scale;
+ y1 = (y + (i + 1) * (line_height + 5)) * scale;
+
+ plot.clip(x0, y0, x1, y1);
+ if (option->selected) {
+ colour = 0xDB9370;
+ plot.clg(colour);
+ }
+ else
+ colour = 0xDDDDDD;
+
+ y0 = y + i * (line_height + 5) + (int) (line_height * 0.75) + 5;
+ y0 *= scale;
+ plot.text((x + box->border[3] + box->padding[3]) * scale, y0,
+ box->style, option->text, strlen(option->text),
+ colour, 0x000000);
+
+ i++;
+ option = option->next;
+ }
+
+ y0 = y * scale;
+ y1 = (y + height) * scale;
+ plot.clip(x0, y0, x1, y1);
+ plot.rectangle(x0, y0, width * scale, height * scale, 1, 0x000000,
+ false, false);
+
+ if (want_knockout)
+ knockout_plot_end();
+
+ return result;
+}
+
+void form_select_menu_clicked(struct browser_window *bw,
+ struct form_control *control, int x, int y)
+{
+ struct box *box;
+ struct form_option *option;
+ int line_height;
+ int i;
+
+ box = visible_select_menu->box;
+
+ line_height = css_len2px(&(box->style->font_size.value.length),
+ box->style);
+ option = visible_select_menu->data.select.items;
+ i = 0;
+ while (option && y > (line_height + 5)) {
+ y -= line_height + 5;
+ i++;
+ option = option->next;
+ }
+
+ if (option)
+ browser_window_form_select(bw, visible_select_menu, i);
+
+ form_redraw_select_menu(bw, 1);
+}
Index: render/form.h
===================================================================
--- render/form.h (wersja 7073)
+++ render/form.h (kopia robocza)
@@ -31,6 +31,8 @@
struct form_control;
struct form_option;
+struct form_control *visible_select_menu;
+
/** Form submit method. */
typedef enum {
method_GET, /**< GET, always url encoded. */
@@ -105,6 +107,7 @@
int num_selected;
/** Currently selected item, if num_selected == 1. */
struct form_option *current;
+ int height;
} select;
} data;
@@ -144,5 +147,7 @@
char *form_url_encode(struct form *form,
struct form_successful_control *control);
void form_free_successful(struct form_successful_control *control);
-
+bool form_show_select_menu(struct browser_window *bw, struct form_control *control);
+bool form_hide_select_menu(struct browser_window *bw);
+void form_select_menu_clicked(struct browser_window *bw, struct form_control *control, int x, int y);
#endif
Index: gtk/gtk_window.c
===================================================================
--- gtk/gtk_window.c (wersja 7073)
+++ gtk/gtk_window.c (kopia robocza)
@@ -411,6 +411,19 @@
bool shift = event->state & GDK_SHIFT_MASK;
bool ctrl = event->state & GDK_CONTROL_MASK;
+ current_widget = widget;
+ current_drawable = widget->window;
+ current_gc = gdk_gc_new(current_drawable);
+#ifdef CAIRO_VERSION
+ current_cr = gdk_cairo_create(current_drawable);
+#endif
+
+ plot = nsgtk_plotters;
+ nsgtk_plot_set_scale(g->bw->scale);
+ current_redraw_browser = g->bw;
+
+
+
/* If the mouse state is PRESS then we are waiting for a release to emit
* a click event, otherwise just reset the state to nothing*/
if (g->mouse->state & BROWSER_MOUSE_PRESS_1)
@@ -430,6 +443,16 @@
else
browser_window_mouse_drag_end(g->bw, 0, event->x, event->y);
+
+ current_redraw_browser = NULL;
+
+ g_object_unref(current_gc);
+#ifdef CAIRO_VERSION
+ cairo_destroy(current_cr);
+#endif
+
+
+
g->mouse->state = 0;
return TRUE;
}
Index: desktop/browser.c
===================================================================
--- desktop/browser.c (wersja 7073)
+++ desktop/browser.c (kopia robocza)
@@ -1409,6 +1409,31 @@
bw->drag_type = DRAGGING_NONE;
bw->scrolling_box = NULL;
+
+ if (visible_select_menu != NULL) {
+ int x0, y0, x1, y1;
+ box = visible_select_menu->box;
+ box_coords(box, &box_x, &box_y);
+ x0 = box_x - box->border[3];
+ y0 = box_y + box->height + box->border[2] + box->padding[2]
+ + box->padding[0];
+ x1 = box_x + box->width + box->border[1] + box->border[3]
+ + box->padding[1] + box->padding[3];
+ y1 = y0 + visible_select_menu->data.select.height;
+
+ if (x > x0 && x < x1 && y > y0 && y < y1
+ && mouse & BROWSER_MOUSE_CLICK_1) {
+
+ form_select_menu_clicked(bw, visible_select_menu,
+ x - x0,
+ y - y0);
+ }
+ else if (mouse & BROWSER_MOUSE_CLICK_1)
+ form_hide_select_menu(bw);
+
+ return;
+ }
+
/* search the box tree for a link, imagemap, form control, or
* box with scrollbars */
@@ -1499,7 +1524,8 @@
status = messages_get("FormSelect");
pointer = GUI_POINTER_MENU;
if (mouse & BROWSER_MOUSE_CLICK_1)
- gui_create_form_select_menu(bw, gadget);
+ //gui_create_form_select_menu(bw, gadget);
+ form_show_select_menu(bw, gadget);
break;
case GADGET_CHECKBOX:
status = messages_get("FormCheckbox");