URI: 
       tAdd basic drawing area - ltk - Socket-based GUI for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit a664daed365f583f4a5dc42b31f2f80ceeb83b4d
   DIR parent 85b5c97bb7c4e1b85f9c322d1beccd1911f0bf09
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Sat,  6 Jun 2020 20:48:53 +0200
       
       Add basic drawing area
       
       Diffstat:
         M Makefile                            |       2 +-
         M button.c                            |      18 +++++++++---------
         A draw.c                              |     335 +++++++++++++++++++++++++++++++
         A draw.h                              |      42 +++++++++++++++++++++++++++++++
         M ltk.c                               |      21 +++++++++++++--------
         M ltk.h                               |       5 +++--
         A test_draw.gui                       |      10 ++++++++++
       
       7 files changed, 413 insertions(+), 20 deletions(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       t@@ -1,7 +1,7 @@
        LIBS = -lm `pkg-config --libs x11 fontconfig`
        STD = -std=c99
        CFLAGS = -g -w -fcommon -Wall -Werror -Wextra `pkg-config --cflags x11 fontconfig` -pedantic
       -OBJ = text_line.o text_common.o stb_truetype.o ltk.o ini.o grid.o button.o
       +OBJ = text_line.o text_common.o stb_truetype.o ltk.o ini.o grid.o button.o draw.o
        COMPATOBJ = 
        # Uncomment if not using OpenBSD
        #COMPATOBJ = strtonum.o
   DIR diff --git a/button.c b/button.c
       t@@ -58,23 +58,23 @@ ltk_button_ini_handler(ltk_window *window, const char *prop, const char *value) 
                } else if (strcmp(prop, "pad") == 0) {
                        theme->button->pad = atoi(value);
                } else if (strcmp(prop, "border") == 0) {
       -                theme->button->border = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->border);
                } else if (strcmp(prop, "fill") == 0) {
       -                theme->button->fill = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->fill);
                } else if (strcmp(prop, "border_pressed") == 0) {
       -                theme->button->border_pressed = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->border_pressed);
                } else if (strcmp(prop, "fill_pressed") == 0) {
       -                theme->button->fill_pressed = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->fill_pressed);
                } else if (strcmp(prop, "border_active") == 0) {
       -                theme->button->border_active = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->border_active);
                } else if (strcmp(prop, "fill_active") == 0) {
       -                theme->button->fill_active = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->fill_active);
                } else if (strcmp(prop, "border_disabled") == 0) {
       -                theme->button->border_disabled = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->border_disabled);
                } else if (strcmp(prop, "fill_disabled") == 0) {
       -                theme->button->fill_disabled = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->fill_disabled);
                } else if (strcmp(prop, "text_color") == 0) {
       -                theme->button->text_color = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &theme->button->text_color);
                } else {
                        (void)printf("WARNING: Unknown property \"%s\" for button style.\n", prop);
                }
   DIR diff --git a/draw.c b/draw.c
       t@@ -0,0 +1,335 @@
       +/*
       + * This file is part of the Lumidify ToolKit (LTK)
       + * Copyright (c) 2020 lumidify <nobody@lumidify.org>
       + *
       + * Permission is hereby granted, free of charge, to any person obtaining a copy
       + * of this software and associated documentation files (the "Software"), to deal
       + * in the Software without restriction, including without limitation the rights
       + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       + * copies of the Software, and to permit persons to whom the Software is
       + * furnished to do so, subject to the following conditions:
       + *
       + * The above copyright notice and this permission notice shall be included in all
       + * copies or substantial portions of the Software.
       + *
       + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       + * SOFTWARE.
       + */
       +
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <X11/Xlib.h>
       +#include <X11/Xutil.h>
       +#include "util.h"
       +#include "khash.h"
       +#include "stb_truetype.h"
       +#include <fontconfig/fontconfig.h>
       +#include "text_common.h"
       +#include "ltk.h"
       +#include "draw.h"
       +
       +static void ltk_draw_draw(ltk_draw *draw);
       +static ltk_draw *ltk_draw_create(ltk_window *window,
       +    const char *id, int w, int h, const char *color);
       +static void ltk_draw_resize(ltk_draw *draw, int orig_w, int orig_h);
       +static void ltk_draw_destroy(ltk_draw *draw, int shallow);
       +static void ltk_draw_clear(ltk_window *window, ltk_draw *draw);
       +static void ltk_draw_set_color(ltk_window *window, ltk_draw *draw, const char *color);
       +static void ltk_draw_line(ltk_window *window, ltk_draw *draw, int x1, int y1, int x2, int y2);
       +static void ltk_draw_rect(ltk_window *window, ltk_draw *draw, int x, int y, int w, int h, int fill);
       +static void ltk_draw_cmd_clear(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens);
       +static void ltk_draw_cmd_set_color(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens);
       +static void ltk_draw_cmd_line(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens);
       +static void ltk_draw_cmd_rect(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens);
       +static void ltk_draw_cmd_create(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens);
       +
       +static void
       +ltk_draw_draw(ltk_draw *draw) {
       +        ltk_window *window = draw->widget.window;
       +        ltk_rect rect = draw->widget.rect;
       +        XCopyArea(window->dpy, draw->pix, window->xwindow, window->gc, 0, 0, rect.w, rect.h, rect.x, rect.y);
       +}
       +
       +
       +static ltk_draw *
       +ltk_draw_create(ltk_window *window, const char *id, int w, int h, const char *color) {
       +        XWindowAttributes attrs;
       +        ltk_draw *draw = malloc(sizeof(ltk_draw));
       +        if (!draw) ltk_fatal("ERROR: Unable to allocate memory for ltk_draw.\n");
       +
       +        ltk_fill_widget_defaults(&draw->widget, id, window,
       +            &ltk_draw_draw, &ltk_draw_destroy, 1, LTK_DRAW);
       +        draw->widget.resize = &ltk_draw_resize;
       +        draw->widget.rect.w = w;
       +        draw->widget.rect.h = h;
       +        XGetWindowAttributes(window->dpy, window->xwindow, &attrs);
       +        draw->depth = attrs.depth;
       +        draw->pix = XCreatePixmap(window->dpy, window->xwindow, w, h, draw->depth);
       +        if (!ltk_create_xcolor(window, color, &draw->bg)) {
       +                free(draw);
       +                return NULL;
       +        }
       +        draw->fg = draw->bg;
       +        XSetForeground(window->dpy, window->gc, draw->bg.pixel);
       +        XFillRectangle(window->dpy, draw->pix, window->gc, 0, 0, w, h);
       +
       +        return draw;
       +}
       +
       +static void
       +ltk_draw_resize(ltk_draw *draw, int orig_w, int orig_h) {
       +        Window win;
       +        int x, y, w, h, bw, d;
       +        int new_w, new_h;
       +        ltk_window *window = draw->widget.window;
       +        ltk_rect rect = draw->widget.rect;
       +        XGetGeometry(window->dpy, draw->pix, &win, &x, &y, &w, &h, &bw, &d);
       +
       +        new_w = w < rect.w ? rect.w : w;
       +        new_h = h < rect.h ? rect.h : h;
       +        if (new_w < w && new_h < h)
       +                return;
       +        Pixmap tmp = XCreatePixmap(window->dpy, window->xwindow,
       +            new_w, new_h, draw->depth);
       +        XSetForeground(window->dpy, window->gc, draw->bg.pixel);
       +        XFillRectangle(window->dpy, tmp, window->gc, 0, 0, new_w, new_h);
       +        XCopyArea(window->dpy, draw->pix, tmp, window->gc,
       +            0, 0, w, h, 0, 0);
       +        XFreePixmap(window->dpy, draw->pix);
       +        draw->pix = tmp;
       +}
       +
       +static void
       +ltk_draw_destroy(ltk_draw *draw, int shallow) {
       +        if (!draw) {
       +                (void)printf("WARNING: Tried to destroy NULL draw.\n");
       +                return;
       +        }
       +        ltk_remove_widget(draw->widget.window, draw->widget.id);
       +        free(draw->widget.id);
       +        XFreePixmap(draw->widget.window->dpy, draw->pix);
       +        free(draw);
       +}
       +
       +static void
       +ltk_draw_clear(ltk_window *window, ltk_draw *draw) {
       +        Window win;
       +        int x, y, w, h, bw, d;
       +        XGetGeometry(window->dpy, draw->pix, &win, &x, &y, &w, &h, &bw, &d);
       +        XSetForeground(window->dpy, window->gc, draw->bg.pixel);
       +        XFillRectangle(window->dpy, window->xwindow, window->gc, 0, 0, w, h);
       +        ltk_window_invalidate_rect(window, draw->widget.rect);
       +}
       +
       +static void
       +ltk_draw_set_color(ltk_window *window, ltk_draw *draw, const char *color) {
       +        XColor tmp;
       +        if (ltk_create_xcolor(window, color, &tmp)) {
       +                draw->fg = tmp;
       +        }
       +}
       +
       +static void
       +ltk_draw_line(ltk_window *window, ltk_draw *draw, int x1, int y1, int x2, int y2) {
       +        XSetForeground(window->dpy, window->gc, draw->fg.pixel);
       +        XSetLineAttributes(window->dpy, window->gc, 2, LineSolid, CapButt, JoinMiter);
       +        XDrawLine(window->dpy, draw->pix, window->gc, x1, y1, x2, y2);
       +        ltk_window_invalidate_rect(window, draw->widget.rect);
       +}
       +
       +static void
       +ltk_draw_rect(ltk_window *window, ltk_draw *draw, int x, int y, int w, int h, int fill) {
       +        XSetForeground(window->dpy, window->gc, draw->fg.pixel);
       +        if (fill) {
       +                XFillRectangle(window->dpy, window->xwindow, window->gc, x, y, w, h);
       +        } else {
       +                XSetLineAttributes(window->dpy, window->gc, 2, LineSolid, CapButt, JoinMiter);
       +                XDrawRectangle(window->dpy, draw->pix, window->gc, x, y, w, h);
       +        }
       +        ltk_window_invalidate_rect(window, draw->widget.rect);
       +}
       +
       +static void
       +ltk_draw_cmd_clear(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens) {
       +        ltk_draw *draw;
       +        if (num_tokens != 3) {
       +                (void)fprintf(stderr, "draw clear: Invalid number of arguments.\n");
       +                return;
       +        }
       +        draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw clear");
       +        if (!draw) return;
       +        ltk_draw_clear(window, draw);
       +}
       +
       +static void
       +ltk_draw_cmd_set_color(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens) {
       +        ltk_draw *draw;
       +        if (num_tokens != 4) {
       +                (void)fprintf(stderr, "draw set-color: Invalid number of arguments.\n");
       +                return;
       +        }
       +        draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw set-color");
       +        if (!draw) return;
       +        ltk_draw_set_color(window, draw, tokens[3]);
       +}
       +
       +static void
       +ltk_draw_cmd_line(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens) {
       +        ltk_draw *draw;
       +        int x1, y1, x2, y2;
       +        const char *errstr;
       +        if (num_tokens != 7) {
       +                (void)fprintf(stderr, "draw line: Invalid number of arguments.\n");
       +                return;
       +        }
       +        draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw line");
       +        if (!draw) return;
       +        x1 = strtonum(tokens[3], 0, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw line: Invalid x1: %s\n", errstr);
       +                return;
       +        }
       +        y1 = strtonum(tokens[4], 0, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw line: Invalid y1: %s\n", errstr);
       +                return;
       +        }
       +        x2 = strtonum(tokens[5], 0, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw line: Invalid x2: %s\n", errstr);
       +                return;
       +        }
       +        y2 = strtonum(tokens[6], 0, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw line: Invalid y2: %s\n", errstr);
       +                return;
       +        }
       +        ltk_draw_line(window, draw, x1, y1, x2, y2);
       +}
       +
       +static void
       +ltk_draw_cmd_rect(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens) {
       +        ltk_draw *draw;
       +        const char *errstr;
       +        int x, y, w, h, fill;
       +        if (num_tokens != 8) {
       +                (void)fprintf(stderr, "draw clear: Invalid number of arguments.\n");
       +                return;
       +        }
       +        draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw clear");
       +        if (!draw) return;
       +        x = strtonum(tokens[3], 0, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw rect: Invalid x: %s\n", errstr);
       +                return;
       +        }
       +        y = strtonum(tokens[4], 0, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw rect: Invalid y: %s\n", errstr);
       +                return;
       +        }
       +        w = strtonum(tokens[5], 1, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw rect: Invalid width: %s\n", errstr);
       +                return;
       +        }
       +        h = strtonum(tokens[6], 1, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw rect: Invalid height: %s\n", errstr);
       +                return;
       +        }
       +        fill = strtonum(tokens[7], 0, 1, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw rect: Invalid fill bool: %s\n", errstr);
       +                return;
       +        }
       +        ltk_draw_rect(window, draw, x, y, w, h, fill);
       +}
       +
       +/* draw <draw id> create <width> <height> <color> */
       +static void
       +ltk_draw_cmd_create(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens) {
       +        ltk_draw *draw;
       +        int w, h;
       +        const char *errstr;
       +        if (num_tokens != 6) {
       +                (void)fprintf(stderr, "draw create: Invalid number of arguments.\n");
       +                return;
       +        }
       +        if (!ltk_check_widget_id_free(window, tokens[1], "draw create"))
       +                return;
       +        w = strtonum(tokens[3], 1, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw create: Invalid width: %s\n", errstr);
       +                return;
       +        }
       +        h = strtonum(tokens[4], 1, 100000, &errstr);
       +        if (errstr) {
       +                (void)fprintf(stderr, "draw create: Invalid height: %s\n", errstr);
       +                return;
       +        }
       +        draw = ltk_draw_create(window, tokens[1], w, h, tokens[5]);
       +        if (draw)
       +                ltk_set_widget(window, draw, tokens[1]);
       +}
       +
       +/* draw <draw id> <command> ... */
       +void
       +ltk_draw_cmd(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens) {
       +        if (num_tokens < 3) {
       +                (void)fprintf(stderr, "draw: Invalid number of arguments.\n");
       +                return;
       +        }
       +        if (strcmp(tokens[2], "create") == 0) {
       +                ltk_draw_cmd_create(window, tokens, num_tokens);
       +        } else if (strcmp(tokens[2], "clear") == 0) {
       +                ltk_draw_cmd_clear(window, tokens, num_tokens);
       +        } else if (strcmp(tokens[2], "set-color") == 0) {
       +                ltk_draw_cmd_set_color(window, tokens, num_tokens);
       +        } else if (strcmp(tokens[2], "line") == 0) {
       +                ltk_draw_cmd_line(window, tokens, num_tokens);
       +        } else if (strcmp(tokens[2], "rect") == 0) {
       +                ltk_draw_cmd_rect(window, tokens, num_tokens);
       +        } else {
       +                (void)fprintf(stderr, "draw: Invalid command.\n");
       +        }
       +}
   DIR diff --git a/draw.h b/draw.h
       t@@ -0,0 +1,42 @@
       +/*
       + * This file is part of the Lumidify ToolKit (LTK)
       + * Copyright (c) 2020 lumidify <nobody@lumidify.org>
       + *
       + * Permission is hereby granted, free of charge, to any person obtaining a copy
       + * of this software and associated documentation files (the "Software"), to deal
       + * in the Software without restriction, including without limitation the rights
       + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       + * copies of the Software, and to permit persons to whom the Software is
       + * furnished to do so, subject to the following conditions:
       + *
       + * The above copyright notice and this permission notice shall be included in all
       + * copies or substantial portions of the Software.
       + *
       + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       + * SOFTWARE.
       + */
       +
       +#ifndef _LTK_DRAW_H_
       +#define _LTK_DRAW_H_
       +
       +/* Requires the following includes: <X11/Xlib.h>, "ltk.h" */
       +
       +typedef struct {
       +        ltk_widget widget;
       +        Pixmap pix;
       +        int depth;
       +        XColor fg;
       +        XColor bg;
       +} ltk_draw;
       +
       +void ltk_draw_cmd(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens);
       +
       +#endif /* _LTK_DRAW_H_ */
   DIR diff --git a/ltk.c b/ltk.c
       t@@ -41,6 +41,7 @@
        #include "grid.h"
        #include "text_line.h"
        #include "button.h"
       +#include "draw.h"
        
        static void ltk_load_theme(ltk_window *window, const char *path);
        static void ltk_destroy_theme(ltk_theme *theme);
       t@@ -109,13 +110,15 @@ ltk_fatal(const char *msg) {
                exit(1);
        };
        
       -XColor
       -ltk_create_xcolor(ltk_window *window, const char *hex) {
       -        XColor color;
       -        XParseColor(window->dpy, window->cm, hex, &color);
       -        XAllocColor(window->dpy, window->cm, &color);
       +int
       +ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col) {
       +        if (!XParseColor(window->dpy, window->cm, hex, col)) {
       +                (void)fprintf(stderr, "Invalid color: %s\n", hex);
       +                return 0;
       +        }
       +        XAllocColor(window->dpy, window->cm, col);
        
       -        return color;
       +        return 1;
        }
        
        void
       t@@ -231,6 +234,8 @@ proc_cmds(ltk_window *window) {
                        ltk_button_cmd(window, tokens, tokens_len);
                } else if (strcmp(tokens[0], "set-root-widget") == 0) {
                        ltk_set_root_widget_cmd(window, tokens, tokens_len);
       +        } else if (strcmp(tokens[0], "draw") == 0) {
       +                ltk_draw_cmd(window, tokens, tokens_len);
                } else {
                        (void)fprintf(stderr, "Invalid command.\n");
                }
       t@@ -406,9 +411,9 @@ ltk_window_ini_handler(ltk_window *window, const char *prop, const char *value) 
                if (strcmp(prop, "border_width") == 0) {
                        window->theme->window->border_width = atoi(value);
                } else if (strcmp(prop, "bg") == 0) {
       -                window->theme->window->bg = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &window->theme->window->bg);
                } else if (strcmp(prop, "fg") == 0) {
       -                window->theme->window->fg = ltk_create_xcolor(window, value);
       +                ltk_create_xcolor(window, value, &window->theme->window->fg);
                } else if (strcmp(prop, "font") == 0) {
                        window->theme->window->font = strdup(value);
                } else if (strcmp(prop, "font_size") == 0) {
   DIR diff --git a/ltk.h b/ltk.h
       t@@ -24,7 +24,7 @@
        #ifndef _LTK_H_
        #define _LTK_H_
        
       -/* Requires the following includes: <X11/Xlib.h>, <X11/Xutil.h>, "drw.h" */
       +/* Requires the following includes: <X11/Xlib.h>, <X11/Xutil.h> */
        
        typedef struct {
                int x;
       t@@ -50,6 +50,7 @@ typedef enum {
        typedef enum {
                LTK_GRID,
                LTK_BUTTON,
       +        LTK_DRAW,
                LTK_WIDGET
        } ltk_widget_type;
        
       t@@ -133,7 +134,7 @@ void ltk_window_invalidate_rect(ltk_window *window, ltk_rect rect);
        
        void ltk_fatal(const char *msg);
        
       -XColor ltk_create_xcolor(ltk_window *window, const char *hex);
       +int ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col);
        
        void ltk_queue_event(ltk_window *window, const char *id, const char *name);
        
   DIR diff --git a/test_draw.gui b/test_draw.gui
       t@@ -0,0 +1,10 @@
       +grid grd1 create 2 2
       +grid grd1 set-row-weight 0 1
       +grid grd1 set-row-weight 1 1
       +grid grd1 set-column-weight 0 1
       +grid grd1 set-column-weight 1 1
       +set-root-widget grd1
       +draw drw1 create 100 100 #fff
       +grid grd1 add drw1 0 1 1 1 15
       +draw drw1 set-color #000
       +draw drw1 line 0 0 100 100