Commit b676840e authored by Jody Goldberg's avatar Jody Goldberg

- More work on array-formulas, still no cut/copy/paste. But its harder

  to cause a core dump :-)  Some docs.
- Have patterns match Excel.
- Easy optimization in the common case to do 1 intersection rather than 4
    for a single cell.
- Some command line flags for debugging excel import.
parent cbbbdf84
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
......@@ -129,7 +129,13 @@ documentation for these:
- Home: move to the beginning of the row.
- Contorl-Home: move to the cell A1
- Control-Home: move to the cell A1
- Control-Enter: copies current edit text to the selected range.
- Control-Shift-Enter: If there is a single range selected and the
current edit text is a formula, the formula is made into an
'array-formula'
o Auto-convert-on-input features: When you enter text in Gnumeric
it is now matched against the known formats of Gnumeric and if
......@@ -140,3 +146,11 @@ documentation for these:
this: ="10-Jan"+45.
Autofill will also work on this.
o Gnumeric command line debug arguments.
- dump-func-defs
- debug
- debug_excel_read
- debug_excel_formulas
- debug_excel_color
- debug_excel_chart
......@@ -53,9 +53,9 @@ cell_set_formula (Cell *cell, const char *text)
cell_modified (cell);
new_expr = expr_parse_string (&text [1],
eval_pos_cell (&fp, cell),
&desired_format,
&error_msg);
eval_pos_cell (&fp, cell),
&desired_format,
&error_msg);
if (new_expr == NULL){
cell->parsed_node = NULL;
cell->flags |= CELL_ERROR;
......@@ -67,31 +67,40 @@ cell_set_formula (Cell *cell, const char *text)
return;
}
if (new_expr->oper == OPER_ARRAY){
if (new_expr->u.array.x == 0 && new_expr->u.array.y == 0){
cell->parsed_node = new_expr;
cell_set_array_formula (cell->sheet,
cell->row->pos,
cell->col->pos,
cell->row->pos + new_expr->u.array.rows -1,
cell->col->pos + new_expr->u.array.cols -1,
new_expr->u.array.corner.func.expr);
} else
new_expr = NULL;
} else
cell->parsed_node = new_expr;
if (cell->flags & CELL_ERROR)
cell->flags &= ~CELL_ERROR;
if (cell->flags & CELL_ERROR)
cell->flags &= ~CELL_ERROR;
if (desired_format && strcmp (cell->style->format->format, "General") == 0){
if (desired_format &&
strcmp (cell->style->format->format, "General") == 0){
style_format_unref (cell->style->format);
cell->style->format = style_format_new (desired_format);
}
/* Don't touch things if this was part of an array not at the corner */
if (new_expr)
cell_formula_changed (cell);
if (new_expr->oper == OPER_ARRAY){
/* The corner sets up the entire array block */
if (new_expr->u.array.x != 0 || new_expr->u.array.y != 0)
{
expr_tree_unref (new_expr);
return;
}
/*
* NOTE : The wrapper supplied by the parser will be released
* and recreated. new_expr will NOT be valid on exit
* from cell_set_array_formula.
*/
cell->parsed_node = new_expr;
cell_set_array_formula (cell->sheet,
cell->row->pos, cell->col->pos,
cell->row->pos +
new_expr->u.array.rows -1,
cell->col->pos +
new_expr->u.array.cols -1,
new_expr->u.array.corner.func.expr);
} else {
cell->parsed_node = new_expr;
cell_formula_changed (cell);
}
}
/*
......@@ -706,6 +715,7 @@ cell_content_changed (Cell *cell)
cell_queue_recalc_list (deps, TRUE);
}
/*
* cell_set_text
*
......@@ -717,6 +727,12 @@ cell_set_text (Cell *cell, const char *text)
g_return_if_fail (cell != NULL);
g_return_if_fail (text != NULL);
if (cell->parsed_node != NULL && cell->parsed_node->oper == OPER_ARRAY)
{
gnumeric_no_modify_array_notice (cell->sheet->workbook);
return;
}
cell_queue_redraw (cell);
cell_set_text_simple (cell, text);
......
......@@ -334,7 +334,7 @@ typedef struct {
int end_col, end_row;
Sheet *sheet;
GList *list;
} get_dep_closure_t;
} get_range_dep_closure_t;
static gboolean
intersects (Sheet *sheet, int col, int row, DependencyRange *range)
......@@ -347,10 +347,10 @@ intersects (Sheet *sheet, int col, int row, DependencyRange *range)
}
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
search_range_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_dep_closure_t *c = closure;
get_range_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
......@@ -372,7 +372,7 @@ search_cell_deps (gpointer key, gpointer value, gpointer closure)
GList *
region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col, int end_row)
{
get_dep_closure_t closure;
get_range_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
......@@ -384,23 +384,46 @@ region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col
closure.sheet = sheet;
closure.list = NULL;
g_hash_table_foreach (dependency_hash, &search_cell_deps, &closure);
g_hash_table_foreach (dependency_hash, &search_range_deps, &closure);
return closure.list;
}
typedef struct {
int col, row;
Sheet *sheet;
GList *list;
} get_cell_dep_closure_t;
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_cell_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
/* No intersection is the common case */
if (!intersects (sheet, c->col, c->row, range))
return;
for (l = range->cell_list; l; l = l->next){
Cell *cell = l->data;
c->list = g_list_prepend (c->list, cell);
}
}
GList *
cell_get_dependencies (Sheet *sheet, int col, int row)
{
get_dep_closure_t closure;
get_cell_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
closure.start_col = col;
closure.start_row = row;
closure.end_col = col;
closure.end_row = row;
closure.col = col;
closure.row = row;
closure.sheet = sheet;
closure.list = NULL;
......@@ -539,14 +562,28 @@ workbook_recalc (Workbook *wb)
cell->generation = generation;
cell_eval (cell);
deps = cell_get_dependencies (cell->sheet, cell->col->pos, cell->row->pos);
deps = cell_get_dependencies (cell->sheet,
cell->col->pos, cell->row->pos);
#ifdef DEBUG_EVALUATION
printf ("\nDepends for %s:%s :\n",
cell->sheet->name,
cell_name(cell->col->pos, cell->row->pos));
#endif
for (l = deps; l; l = l->next){
Cell *one_cell;
one_cell = l->data;
if (one_cell->generation != generation)
if (one_cell->generation != generation){
cell_queue_recalc (one_cell);
#ifdef DEBUG_EVALUATION
printf ("\t%s:%s,\n",
one_cell->sheet->name,
cell_name(one_cell->col->pos,
one_cell->row->pos));
#endif
}
}
g_list_free (deps);
}
......
......@@ -334,7 +334,7 @@ typedef struct {
int end_col, end_row;
Sheet *sheet;
GList *list;
} get_dep_closure_t;
} get_range_dep_closure_t;
static gboolean
intersects (Sheet *sheet, int col, int row, DependencyRange *range)
......@@ -347,10 +347,10 @@ intersects (Sheet *sheet, int col, int row, DependencyRange *range)
}
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
search_range_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_dep_closure_t *c = closure;
get_range_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
......@@ -372,7 +372,7 @@ search_cell_deps (gpointer key, gpointer value, gpointer closure)
GList *
region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col, int end_row)
{
get_dep_closure_t closure;
get_range_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
......@@ -384,23 +384,46 @@ region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col
closure.sheet = sheet;
closure.list = NULL;
g_hash_table_foreach (dependency_hash, &search_cell_deps, &closure);
g_hash_table_foreach (dependency_hash, &search_range_deps, &closure);
return closure.list;
}
typedef struct {
int col, row;
Sheet *sheet;
GList *list;
} get_cell_dep_closure_t;
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_cell_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
/* No intersection is the common case */
if (!intersects (sheet, c->col, c->row, range))
return;
for (l = range->cell_list; l; l = l->next){
Cell *cell = l->data;
c->list = g_list_prepend (c->list, cell);
}
}
GList *
cell_get_dependencies (Sheet *sheet, int col, int row)
{
get_dep_closure_t closure;
get_cell_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
closure.start_col = col;
closure.start_row = row;
closure.end_col = col;
closure.end_row = row;
closure.col = col;
closure.row = row;
closure.sheet = sheet;
closure.list = NULL;
......@@ -539,14 +562,28 @@ workbook_recalc (Workbook *wb)
cell->generation = generation;
cell_eval (cell);
deps = cell_get_dependencies (cell->sheet, cell->col->pos, cell->row->pos);
deps = cell_get_dependencies (cell->sheet,
cell->col->pos, cell->row->pos);
#ifdef DEBUG_EVALUATION
printf ("\nDepends for %s:%s :\n",
cell->sheet->name,
cell_name(cell->col->pos, cell->row->pos));
#endif
for (l = deps; l; l = l->next){
Cell *one_cell;
one_cell = l->data;
if (one_cell->generation != generation)
if (one_cell->generation != generation){
cell_queue_recalc (one_cell);
#ifdef DEBUG_EVALUATION
printf ("\t%s:%s,\n",
one_cell->sheet->name,
cell_name(one_cell->col->pos,
one_cell->row->pos));
#endif
}
}
g_list_free (deps);
}
......
......@@ -260,6 +260,17 @@ expr_tree_get_const_int (ExprTree const * const expr)
return expr->u.constant->v.v_int;
}
char const *
expr_tree_get_const_str (ExprTree const *const expr)
{
g_return_val_if_fail (expr != NULL, NULL);
g_return_val_if_fail (expr->oper == OPER_CONSTANT, NULL);
g_return_val_if_fail (expr->u.constant, NULL);
g_return_val_if_fail (expr->u.constant->type == VALUE_STRING, NULL);
return expr->u.constant->v.str->str;
}
ExprTree *
expr_parse_string (const char *expr, const EvalPosition *fp,
const char **desired_format, char **error_msg)
......@@ -1669,8 +1680,8 @@ eval_expr (FunctionEvalInfo *s, ExprTree *tree)
else
a = NULL;
}
g_return_val_if_fail (a != NULL,
function_error (s, gnumeric_err_NA));
if (a == NULL) /* Seems like errors return NULL */
return NULL;
if (a->type == VALUE_CELLRANGE || a->type == VALUE_ARRAY){
int const num_x = value_area_get_width (&s->pos, a);
......@@ -1907,7 +1918,7 @@ do_expr_decode_tree (ExprTree *tree, const EvalPosition *fp, int paren_level)
res = do_expr_decode_tree (
array->u.array.corner.func.expr,
&tmp_pos, 0);
}
}
} else
{
res = do_expr_decode_tree (
......@@ -2084,9 +2095,22 @@ do_expr_tree_invalidate_references (ExprTree *src, const struct expr_tree_frob_r
}
case OPER_ARRAY:
{
/* FIXME FIXME FIXME : what should this do ? */
return NULL;
g_assert_not_reached ();
ArrayRef * a = &src->u.array;
if (a->x == 0 && a->y == 0)
{
ExprTree *func = do_expr_tree_invalidate_references (
a->corner.func.expr, info);
if (func != NULL)
{
ExprTree *res =
expr_tree_array_formula (0, 0,
a->rows, a->cols);
res->u.array.corner.func.value = NULL;
res->u.array.corner.func.expr = func;
return res;
}
}
return NULL;
}
}
......@@ -2098,7 +2122,7 @@ do_expr_tree_invalidate_references (ExprTree *src, const struct expr_tree_frob_r
/*
* Invalidate (== turn into error expressions) cell and range references that
* will disappear completely during a deletions of columns or rows. Note that
* this is not intended for use when just the cell contents is delete.
* this is not intended for use when just the cell contents is deleted.
*/
ExprTree *
expr_tree_invalidate_references (ExprTree *src, EvalPosition *src_fp,
......@@ -2296,12 +2320,23 @@ do_expr_tree_fixup_references (ExprTree *src, const struct expr_tree_frob_refere
}
case OPER_ARRAY:
{
/*
* FIXME FIXME FIXME : This is the mirror of above.
* Read and find out what they do
*/
return NULL;
g_assert_not_reached ();
ArrayRef * a = &src->u.array;
if (a->x == 0 && a->y == 0)
{
ExprTree *func =
do_expr_tree_fixup_references (a->corner.func.expr,
info);
if (func != NULL)
{
ExprTree *res =
expr_tree_array_formula (0, 0,
a->rows, a->cols);
res->u.array.corner.func.value = NULL;
res->u.array.corner.func.expr = func;
return res;
}
}
return NULL;
}
}
......
......@@ -264,7 +264,8 @@ ExprTree *expr_tree_fixup_references (ExprTree *src, EvalPosition *src_fp,
const EvalPosition *fp,
int coldelta, int rowdelta);
int expr_tree_get_const_int (ExprTree const * const expr);
int expr_tree_get_const_int (ExprTree const *const expr);
char const * expr_tree_get_const_str (ExprTree const *const expr);
/* Debugging */
void expr_dump_tree (ExprTree *tree);
......
......@@ -855,8 +855,21 @@ format_number (gdouble number, const StyleFormatEntry *style_format_entry)
break;
case '*':
g_warning ("REPEAT FORMAT NOT YET SUPPORTED\n");
{
/* FIXME FIXME FIXME
* this will require an interface change to pass in
* the size of the cell being formated as well as a
* minor reworking of the routines logic to fill in the
* space later.
*/
static gboolean quiet_warning = FALSE;
if (quiet_warning)
break;
quiet_warning = TRUE;
g_warning ("REPEAT FORMAT NOT YET SUPPORTED '%s' %g\n",
style_format_entry->format, number);
break;
}
case 'H':
case 'h':
......
......@@ -742,6 +742,8 @@ gnumeric_sheet_key_mode_sheet (GnumericSheet *gsheet, GdkEventKey *event)
if (gsheet->item_editor){
Cell *cell;
char *text;
gboolean const is_array =
(event->state & GDK_SHIFT_MASK);
sheet_accept_pending_input (sheet);
cell = sheet_cell_get (sheet,
......@@ -756,7 +758,8 @@ gnumeric_sheet_key_mode_sheet (GnumericSheet *gsheet, GdkEventKey *event)
*/
g_return_val_if_fail (cell != NULL, 1);
text = cell_get_text (cell);
sheet_fill_selection_with (sheet, text);
sheet_fill_selection_with (sheet, text,
is_array);
g_free (text);
} else {
gtk_widget_grab_focus (gsheet->entry);
......@@ -908,44 +911,59 @@ gnumeric_sheet_new (SheetView *sheet_view, ItemBar *colbar, ItemBar *rowbar)
}
gnumeric_sheet_pattern_t gnumeric_sheet_patterns [GNUMERIC_SHEET_PATTERNS] = {
{ N_("Solid"),
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ N_("75%"),
{ 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb } },
{ 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee } },
{ N_("50%"),
{ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 } },
{ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 } },
{ N_("25%"),
{ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44 } },
{ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88 } },
{ N_("12.5%"),
{ 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 } },
{ N_("6.25%"),
{ 0x20, 0x00, 0x02, 0x00, 0x20, 0x00, 0x02, 0x00 } },
{ N_("Horizontal Stripe"),
{ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff } },
{ N_("Vertical Stripe"),
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 } },
{ N_("12%"),
{ 0x01, 0x08, 0x40, 0x02, 0x10, 0x80, 0x04, 0x20 } },
{ N_("Reverse Diagonal Stripe"),
{ 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 } },
{ N_("6%"),
{ 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x04, 0x00 } },
{ N_("Diagonal Stripe"),
{ 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc, 0x99 } },
{ N_("Horizontal lines"),
{ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00 } },
{ N_("Diagonal Crosshatch"),
{ 0x99, 0x66, 0x66, 0x99, 0x99, 0x66, 0x66, 0x99 } },
{ N_("Vertical lines"),
{ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } },
{ N_("Thick Diagonal Crosshatch"),
{ 0xff, 0x66, 0xff, 0x99, 0xff, 0x66, 0xff, 0x99 } },
{ N_("Diagonal lines"),
{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 } },
{ N_("Thin Horizontal Stripe"),
{ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00 } },