| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- IMPLEMENTATION MODULE DemosCanvas ;
- (*
- m2-GTK4 - the drawing/canvas gtk-demo demos:
- drawingarea.c -> DoDrawingArea
- gestures.c -> DoGestures
- mask.c -> DoMask
- snapping.c -> DoSnapping
- The gtk-demo contract is: on the first call build the window and store
- it in a module-level variable; on later calls toggle the window's
- visibility, destroying it (and clearing the variable) when it is
- already visible. Return the window, or NIL once destroyed.
- Only bindings under src/ are used, so a few C facilities are missing and
- those spots are simplified (each marked "SIMPLIFIED" below):
- * gtk_widget_queue_draw() is not bound. Gesture/scribble state is
- still recorded, but the drawing areas cannot be repainted until GTK
- redraws them for another reason (e.g. an expose or resize).
- * drawingarea's groups_draw uses cairo_surface_create_similar(),
- cairo_get_target() and CAIRO_OPERATOR_DEST_OUT/ADD, none of which
- are bound; the knockout/composite is approximated by a black disc
- with the three coloured sub-discs drawn on top.
- * cairo_image_surface_get_width()/get_height() are not bound, so the
- scribble surface is (re)created on the "resize" signal only.
- * gtk_window_set_display(), the accessible-role/an accessible-relation
- setup and g_object_new(drawing area) are not bound; a plain
- gtk_drawing_area_new() is used.
- * gestures' rotate/zoom visualisation reads the gesture deltas from
- the signal arguments instead of gtk_gesture_*_get_*_delta(), and uses
- the widget centre instead of gtk_gesture_get_bounding_box_center();
- the touchpad 3-finger swipe and gtk_gesture_is_recognized() are not
- reproduced.
- * mask's Demo4Widget is a custom GskMaskNode widget with a Pango
- layout and a frame-clock tick callback; subclassing, GskMaskNode and
- gtk_widget_add_tick_callback() are not bound, so the "123" text is
- filled with a moving 8-stop gradient via Cairo instead.
- * snapping's GtkTiler is a custom GdkPaintable; a GtkDrawingArea is
- used instead, drawing the QR code on a pixel-snapped 43x43 grid with
- linear gradients between differing neighbours (the conic/radial
- corner cases are left white).
- *)
- FROM SYSTEM IMPORT ADDRESS, ADR;
- FROM GtkWindow IMPORT gtk_window_new, gtk_window_set_title,
- gtk_window_set_default_size, gtk_window_set_child, gtk_window_destroy;
- FROM GtkWidget IMPORT gtk_widget_set_visible, gtk_widget_get_visible,
- gtk_widget_set_margin_start, gtk_widget_set_margin_end,
- gtk_widget_set_margin_top, gtk_widget_set_margin_bottom,
- gtk_widget_set_vexpand, gtk_widget_set_hexpand,
- gtk_widget_add_css_class, gtk_widget_get_width, gtk_widget_get_height,
- gtk_widget_add_controller;
- FROM GtkEnums IMPORT GtkVertical, GtkHorizontal;
- FROM GtkBox IMPORT gtk_box_new, gtk_box_append;
- FROM GtkLabel IMPORT gtk_label_new;
- FROM GtkFrame IMPORT gtk_frame_new, gtk_frame_set_child;
- FROM GtkDrawingArea IMPORT gtk_drawing_area_new,
- gtk_drawing_area_set_content_width, gtk_drawing_area_set_content_height,
- gtk_drawing_area_set_draw_func;
- FROM GtkGestures IMPORT gtk_gesture_drag_new, gtk_gesture_single_set_button,
- gtk_gesture_swipe_new, gtk_gesture_long_press_new,
- gtk_gesture_rotate_new, gtk_gesture_zoom_new;
- FROM GtkEventController IMPORT gtk_event_controller_set_propagation_phase,
- GtkPhaseBubble;
- FROM GtkScale IMPORT gtk_scale_new_with_range;
- FROM GtkRange IMPORT gtk_range_set_value, gtk_range_get_value;
- FROM GObject IMPORT g_signal_connect_data, GConnectDefault;
- FROM GtkClosures IMPORT Connect2;
- FROM Cairo IMPORT
- cairo_create, cairo_destroy, cairo_set_source_rgb, cairo_paint,
- cairo_set_source_surface, cairo_move_to, cairo_line_to,
- cairo_set_line_width, cairo_set_line_cap, cairo_stroke,
- cairo_save, cairo_restore, cairo_translate, cairo_scale, cairo_rotate,
- cairo_arc,
- cairo_close_path, cairo_rectangle, cairo_fill, cairo_set_source_rgba,
- cairo_surface_destroy, cairo_image_surface_create,
- cairo_pattern_create_linear, cairo_pattern_add_color_stop_rgb,
- cairo_set_source, cairo_pattern_destroy, cairo_select_font_face,
- cairo_set_font_size, cairo_text_path,
- CairoFormatARGB32, CairoLineCapRound,
- CairoFontSlantNormal, CairoFontWeightBold;
- CONST
- Pi = 3.14159265358979;
- VAR
- (* drawingarea *)
- drawingWindow, drawSurface: ADDRESS;
- dragStartX, dragStartY: REAL;
- (* gestures *)
- gesturesWindow: ADDRESS;
- swipeX, swipeY, rotateDelta, zoomScale: REAL;
- longPressed, hasRotate, hasZoom: BOOLEAN;
- (* mask *)
- maskWindow, maskScale: ADDRESS;
- maskProgress: REAL;
- (* snapping *)
- snappingWindow: ADDRESS;
- qrData: ARRAY [0..20] OF ARRAY [0..20] OF CHAR;
- (* ------------------------------------------------------------------ *)
- (* small helpers *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE IMin (a, b: INTEGER) : INTEGER;
- BEGIN
- IF a < b THEN RETURN a ELSE RETURN b END
- END IMin;
- (* The 21x21 QR matrix of snapping.c, one row per string. *)
- PROCEDURE InitQrData;
- BEGIN
- qrData[0] := "000000010111110000000";
- qrData[1] := "011111011100110111110";
- qrData[2] := "010001011010010100010";
- qrData[3] := "010001010011110100010";
- qrData[4] := "010001010001010100010";
- qrData[5] := "011111010100110111110";
- qrData[6] := "000000010101010000000";
- qrData[7] := "111111110000011111111";
- qrData[8] := "011101000000100000110";
- qrData[9] := "111100100000011100011";
- qrData[10] := "110010010110110001001";
- qrData[11] := "111001100101101111100";
- qrData[12] := "101100000011001100110";
- qrData[13] := "111111110011011100011";
- qrData[14] := "000000010011000101001";
- qrData[15] := "011111011000001000100";
- qrData[16] := "010001010010111011101";
- qrData[17] := "010001011001000000100";
- qrData[18] := "010001011010110100011";
- qrData[19] := "011111011001001111111";
- qrData[20] := "000000010100001011110"
- END InitQrData;
- (* ------------------------------------------------------------------ *)
- (* drawing area *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE CreateSurface (widget: ADDRESS);
- VAR
- cr: ADDRESS;
- BEGIN
- IF drawSurface # NIL THEN
- cairo_surface_destroy(drawSurface)
- END;
- drawSurface := cairo_image_surface_create(CairoFormatARGB32,
- gtk_widget_get_width(widget),
- gtk_widget_get_height(widget));
- cr := cairo_create(drawSurface);
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_paint(cr);
- cairo_destroy(cr)
- END CreateSurface;
- (* void scribble_resize(GtkWidget *widget, int width, int height, gpointer) *)
- PROCEDURE ScribbleResize (widget: ADDRESS; width, height: INTEGER;
- data: ADDRESS);
- BEGIN
- CreateSurface(widget)
- END ScribbleResize;
- PROCEDURE ScribbleDraw (area: ADDRESS; cr: ADDRESS;
- width, height: INTEGER; data: ADDRESS);
- BEGIN
- IF drawSurface # NIL THEN
- cairo_set_source_surface(cr, drawSurface, 0.0, 0.0);
- cairo_paint(cr)
- END
- END ScribbleDraw;
- PROCEDURE DrawBrush (widget: ADDRESS; x, y: REAL);
- VAR
- cr: ADDRESS;
- BEGIN
- IF drawSurface = NIL THEN
- CreateSurface(widget)
- END;
- cr := cairo_create(drawSurface);
- cairo_move_to(cr, x, y);
- cairo_line_to(cr, x, y);
- cairo_set_line_width(cr, 6.0);
- cairo_set_line_cap(cr, CairoLineCapRound);
- cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- cairo_stroke(cr);
- cairo_destroy(cr)
- (* gtk_widget_queue_draw(widget) is not bound (see header). *)
- END DrawBrush;
- PROCEDURE DragBegin (gesture: ADDRESS; x, y: REAL; area: ADDRESS);
- BEGIN
- dragStartX := x;
- dragStartY := y;
- DrawBrush(area, x, y)
- END DragBegin;
- PROCEDURE DragUpdate (gesture: ADDRESS; x, y: REAL; area: ADDRESS);
- BEGIN
- DrawBrush(area, dragStartX + x, dragStartY + y)
- END DragUpdate;
- PROCEDURE DragEnd (gesture: ADDRESS; x, y: REAL; area: ADDRESS);
- BEGIN
- DrawBrush(area, dragStartX + x, dragStartY + y)
- END DragEnd;
- PROCEDURE OvalPath (cr: ADDRESS; xc, yc, xr, yr: REAL);
- BEGIN
- cairo_save(cr);
- cairo_translate(cr, xc, yc);
- cairo_scale(cr, 1.0, yr / xr);
- cairo_move_to(cr, xr, 0.0);
- cairo_arc(cr, 0.0, 0.0, xr, 0.0, 2.0 * Pi);
- cairo_close_path(cr);
- cairo_restore(cr)
- END OvalPath;
- PROCEDURE FillChecks (cr: ADDRESS; x, y, width, height: INTEGER);
- CONST
- CheckSize = 16;
- VAR
- i, j: INTEGER;
- BEGIN
- cairo_rectangle(cr, VAL(REAL, x), VAL(REAL, y),
- VAL(REAL, width), VAL(REAL, height));
- cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
- cairo_fill(cr);
- (* x & (-CHECK_SIZE), valid for CHECK_SIZE a power of two. *)
- j := x - (x MOD CheckSize);
- WHILE j < height DO
- i := y - (y MOD CheckSize);
- WHILE i < width DO
- IF ((i DIV CheckSize) + (j DIV CheckSize)) MOD 2 = 0 THEN
- cairo_rectangle(cr, VAL(REAL, i), VAL(REAL, j),
- VAL(REAL, CheckSize), VAL(REAL, CheckSize))
- END;
- INC(i, CheckSize)
- END;
- INC(j, CheckSize)
- END;
- cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
- cairo_fill(cr)
- END FillChecks;
- PROCEDURE Draw3Circles (cr: ADDRESS; xc, yc, radius, alpha: REAL);
- CONST
- SubRadius = 0.56666667; (* 2/3 - 0.1 *)
- Third = 0.33333333;
- Cos30 = 0.86602540;
- VAR
- sr: REAL;
- BEGIN
- sr := radius * SubRadius;
- cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, alpha);
- OvalPath(cr, xc, yc - radius * Third, sr, sr);
- cairo_fill(cr);
- cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, alpha);
- OvalPath(cr, xc - radius * Third * Cos30,
- yc + radius * Third * 0.5, sr, sr);
- cairo_fill(cr);
- cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, alpha);
- OvalPath(cr, xc + radius * Third * Cos30,
- yc + radius * Third * 0.5, sr, sr);
- cairo_fill(cr)
- END Draw3Circles;
- PROCEDURE GroupsDraw (area: ADDRESS; cr: ADDRESS;
- width, height: INTEGER; data: ADDRESS);
- VAR
- radius, xc, yc: REAL;
- BEGIN
- radius := 0.5 * VAL(REAL, IMin(width, height)) - 10.0;
- xc := VAL(REAL, width) / 2.0;
- yc := VAL(REAL, height) / 2.0;
- FillChecks(cr, 0, 0, width, height);
- (* SIMPLIFIED: no similar surfaces / DEST_OUT / ADD. *)
- cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- OvalPath(cr, xc, yc, radius, radius);
- cairo_fill(cr);
- Draw3Circles(cr, xc, yc, radius, 1.0)
- END GroupsDraw;
- PROCEDURE OnDrawingDestroy (widget: ADDRESS; data: ADDRESS);
- BEGIN
- IF drawSurface # NIL THEN
- cairo_surface_destroy(drawSurface);
- drawSurface := NIL
- END
- END OnDrawingDestroy;
- PROCEDURE DoDrawingArea (doWidget: ADDRESS) : ADDRESS;
- VAR
- vbox, da, label, frame, drag: ADDRESS;
- BEGIN
- IF drawingWindow = NIL THEN
- drawingWindow := gtk_window_new();
- gtk_window_set_title(drawingWindow, "Drawing Area");
- gtk_window_set_default_size(drawingWindow, 250, -1);
- Connect2(drawingWindow, "destroy", OnDrawingDestroy, NIL);
- vbox := gtk_box_new(GtkVertical, 8);
- gtk_widget_set_margin_start(vbox, 16);
- gtk_widget_set_margin_end(vbox, 16);
- gtk_widget_set_margin_top(vbox, 16);
- gtk_widget_set_margin_bottom(vbox, 16);
- gtk_window_set_child(drawingWindow, vbox);
- (* groups area *)
- label := gtk_label_new("Knockout groups");
- gtk_widget_add_css_class(label, "heading");
- gtk_box_append(vbox, label);
- frame := gtk_frame_new("");
- gtk_widget_set_vexpand(frame, 1);
- gtk_box_append(vbox, frame);
- da := gtk_drawing_area_new();
- gtk_frame_set_child(frame, da);
- gtk_drawing_area_set_content_width(da, 100);
- gtk_drawing_area_set_content_height(da, 100);
- gtk_drawing_area_set_draw_func(da, ADR(GroupsDraw), NIL, NIL);
- (* scribble area *)
- label := gtk_label_new("Scribble area");
- gtk_widget_add_css_class(label, "heading");
- gtk_box_append(vbox, label);
- frame := gtk_frame_new("");
- gtk_widget_set_vexpand(frame, 1);
- gtk_box_append(vbox, frame);
- da := gtk_drawing_area_new();
- gtk_frame_set_child(frame, da);
- gtk_drawing_area_set_content_width(da, 100);
- gtk_drawing_area_set_content_height(da, 100);
- gtk_drawing_area_set_draw_func(da, ADR(ScribbleDraw), NIL, NIL);
- g_signal_connect_data(da, "resize", ADR(ScribbleResize), NIL, NIL,
- GConnectDefault);
- drag := gtk_gesture_drag_new();
- gtk_gesture_single_set_button(drag, 0);
- gtk_widget_add_controller(da, drag);
- g_signal_connect_data(drag, "drag-begin", ADR(DragBegin), da, NIL,
- GConnectDefault);
- g_signal_connect_data(drag, "drag-update", ADR(DragUpdate), da, NIL,
- GConnectDefault);
- g_signal_connect_data(drag, "drag-end", ADR(DragEnd), da, NIL,
- GConnectDefault)
- END;
- IF gtk_widget_get_visible(drawingWindow) = 0 THEN
- gtk_widget_set_visible(drawingWindow, 1)
- ELSE
- gtk_window_destroy(drawingWindow);
- drawingWindow := NIL
- END;
- RETURN drawingWindow
- END DoDrawingArea;
- (* ------------------------------------------------------------------ *)
- (* gestures *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE SwipeSwept (gesture: ADDRESS; vx, vy: REAL; widget: ADDRESS);
- BEGIN
- swipeX := vx / 10.0;
- swipeY := vy / 10.0
- END SwipeSwept;
- PROCEDURE LongPressPressed (gesture: ADDRESS; x, y: REAL; widget: ADDRESS);
- BEGIN
- longPressed := TRUE
- END LongPressPressed;
- PROCEDURE LongPressEnd (gesture: ADDRESS; sequence: ADDRESS; widget: ADDRESS);
- BEGIN
- longPressed := FALSE
- END LongPressEnd;
- PROCEDURE RotationChanged (gesture: ADDRESS; angle, delta: REAL;
- widget: ADDRESS);
- BEGIN
- rotateDelta := delta;
- hasRotate := TRUE
- END RotationChanged;
- PROCEDURE ZoomChanged (gesture: ADDRESS; scale: REAL; widget: ADDRESS);
- BEGIN
- zoomScale := scale;
- hasZoom := TRUE
- END ZoomChanged;
- PROCEDURE GesturesDraw (area: ADDRESS; cr: ADDRESS;
- width, height: INTEGER; data: ADDRESS);
- VAR
- pat: ADDRESS;
- cx, cy: REAL;
- BEGIN
- cx := VAL(REAL, width) / 2.0;
- cy := VAL(REAL, height) / 2.0;
- IF (swipeX # 0.0) OR (swipeY # 0.0) THEN
- cairo_save(cr);
- cairo_set_line_width(cr, 6.0);
- cairo_move_to(cr, cx, cy);
- cairo_line_to(cr, cx + swipeX, cy + swipeY);
- cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.5);
- cairo_stroke(cr);
- cairo_restore(cr)
- END;
- IF hasRotate OR hasZoom THEN
- pat := cairo_pattern_create_linear(-100.0, 0.0, 200.0, 0.0);
- cairo_pattern_add_color_stop_rgb(pat, 0.0, 0.0, 0.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 1.0, 1.0, 0.0, 0.0);
- cairo_save(cr);
- cairo_translate(cr, cx, cy);
- IF hasZoom AND (zoomScale > 0.0) THEN
- cairo_scale(cr, zoomScale, zoomScale)
- END;
- IF hasRotate THEN
- cairo_rotate(cr, rotateDelta)
- END;
- cairo_rectangle(cr, -100.0, -100.0, 200.0, 200.0);
- cairo_set_source(cr, pat);
- cairo_fill(cr);
- cairo_restore(cr);
- cairo_pattern_destroy(pat)
- END;
- IF longPressed THEN
- cairo_save(cr);
- cairo_arc(cr, cx, cy, 50.0, 0.0, 2.0 * Pi);
- cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5);
- cairo_stroke(cr);
- cairo_restore(cr)
- END
- END GesturesDraw;
- PROCEDURE DoGestures (doWidget: ADDRESS) : ADDRESS;
- VAR
- da, gesture: ADDRESS;
- BEGIN
- IF gesturesWindow = NIL THEN
- gesturesWindow := gtk_window_new();
- gtk_window_set_title(gesturesWindow, "Gestures");
- gtk_window_set_default_size(gesturesWindow, 400, 400);
- da := gtk_drawing_area_new();
- gtk_window_set_child(gesturesWindow, da);
- gtk_drawing_area_set_draw_func(da, ADR(GesturesDraw), NIL, NIL);
- (* swipe *)
- gesture := gtk_gesture_swipe_new();
- g_signal_connect_data(gesture, "swipe", ADR(SwipeSwept), da, NIL,
- GConnectDefault);
- gtk_event_controller_set_propagation_phase(gesture, GtkPhaseBubble);
- gtk_widget_add_controller(da, gesture);
- (* long press *)
- gesture := gtk_gesture_long_press_new();
- g_signal_connect_data(gesture, "pressed", ADR(LongPressPressed), da,
- NIL, GConnectDefault);
- g_signal_connect_data(gesture, "end", ADR(LongPressEnd), da, NIL,
- GConnectDefault);
- gtk_event_controller_set_propagation_phase(gesture, GtkPhaseBubble);
- gtk_widget_add_controller(da, gesture);
- (* rotate *)
- gesture := gtk_gesture_rotate_new();
- g_signal_connect_data(gesture, "angle-changed", ADR(RotationChanged),
- da, NIL, GConnectDefault);
- gtk_event_controller_set_propagation_phase(gesture, GtkPhaseBubble);
- gtk_widget_add_controller(da, gesture);
- (* zoom *)
- gesture := gtk_gesture_zoom_new();
- g_signal_connect_data(gesture, "scale-changed", ADR(ZoomChanged), da,
- NIL, GConnectDefault);
- gtk_event_controller_set_propagation_phase(gesture, GtkPhaseBubble);
- gtk_widget_add_controller(da, gesture)
- END;
- IF gtk_widget_get_visible(gesturesWindow) = 0 THEN
- gtk_widget_set_visible(gesturesWindow, 1)
- ELSE
- gtk_window_destroy(gesturesWindow);
- gesturesWindow := NIL
- END;
- RETURN gesturesWindow
- END DoGestures;
- (* ------------------------------------------------------------------ *)
- (* masking *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE OnMaskChanged (range: ADDRESS; data: ADDRESS);
- BEGIN
- maskProgress := gtk_range_get_value(range)
- END OnMaskChanged;
- PROCEDURE MaskDraw (area: ADDRESS; cr: ADDRESS;
- width, height: INTEGER; data: ADDRESS);
- VAR
- pat: ADDRESS;
- w, h, x0, y0: REAL;
- BEGIN
- w := VAL(REAL, width);
- h := VAL(REAL, height);
- cairo_set_source_rgb(cr, 0.08, 0.08, 0.10);
- cairo_rectangle(cr, 0.0, 0.0, w, h);
- cairo_fill(cr);
- (* SIMPLIFIED: fill the "123" glyphs with a moving gradient in place of
- the GskMaskNode composition. *)
- cairo_select_font_face(cr, "sans", CairoFontSlantNormal,
- CairoFontWeightBold);
- cairo_set_font_size(cr, 200.0);
- x0 := w / 2.0 - 165.0;
- y0 := h / 2.0 + 70.0;
- cairo_move_to(cr, x0, y0);
- cairo_text_path(cr, "123");
- pat := cairo_pattern_create_linear(maskProgress * w - w, 0.0,
- maskProgress * w, h);
- cairo_pattern_add_color_stop_rgb(pat, 0.0, 1.0, 0.0, 0.0);
- cairo_pattern_add_color_stop_rgb(pat, 1.0 / 7.0, 1.0, 0.5, 0.0);
- cairo_pattern_add_color_stop_rgb(pat, 2.0 / 7.0, 1.0, 1.0, 0.0);
- cairo_pattern_add_color_stop_rgb(pat, 3.0 / 7.0, 0.0, 1.0, 0.0);
- cairo_pattern_add_color_stop_rgb(pat, 4.0 / 7.0, 0.0, 1.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 5.0 / 7.0, 0.0, 0.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 6.0 / 7.0, 0.6, 0.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 1.0, 1.0, 0.0, 1.0);
- cairo_set_source(cr, pat);
- cairo_fill(cr);
- cairo_pattern_destroy(pat)
- END MaskDraw;
- PROCEDURE DoMask (doWidget: ADDRESS) : ADDRESS;
- VAR
- box, da: ADDRESS;
- BEGIN
- IF maskWindow = NIL THEN
- maskWindow := gtk_window_new();
- gtk_window_set_title(maskWindow, "Mask Nodes");
- gtk_window_set_default_size(maskWindow, 600, 400);
- box := gtk_box_new(GtkVertical, 0);
- gtk_window_set_child(maskWindow, box);
- da := gtk_drawing_area_new();
- gtk_widget_set_hexpand(da, 1);
- gtk_widget_set_vexpand(da, 1);
- gtk_drawing_area_set_draw_func(da, ADR(MaskDraw), NIL, NIL);
- gtk_box_append(box, da);
- maskScale := gtk_scale_new_with_range(GtkHorizontal, 0.0, 1.0, 0.1);
- gtk_range_set_value(maskScale, 0.5);
- maskProgress := 0.5;
- Connect2(maskScale, "value-changed", OnMaskChanged, NIL);
- gtk_box_append(box, maskScale)
- END;
- IF gtk_widget_get_visible(maskWindow) = 0 THEN
- gtk_widget_set_visible(maskWindow, 1)
- ELSE
- gtk_window_destroy(maskWindow);
- maskWindow := NIL
- END;
- RETURN maskWindow
- END DoMask;
- (* ------------------------------------------------------------------ *)
- (* snapping *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE QrOn (x, y: INTEGER) : BOOLEAN;
- BEGIN
- RETURN qrData[y][x] = '1'
- END QrOn;
- PROCEDURE SetOnColor (cr: ADDRESS; on: BOOLEAN);
- BEGIN
- IF on THEN
- cairo_set_source_rgb(cr, 0.2, 0.6, 1.0) (* ON *)
- ELSE
- cairo_set_source_rgb(cr, 1.0, 0.95, 0.7) (* OFF *)
- END
- END SetOnColor;
- (* A 1x1 tile with a horizontal gradient between differing neighbours. *)
- PROCEDURE HBetween (cr: ADDRESS; x, y: REAL; a, b: BOOLEAN);
- VAR
- pat: ADDRESS;
- BEGIN
- IF a = b THEN
- SetOnColor(cr, a)
- ELSE
- pat := cairo_pattern_create_linear(x, y, x + 1.0, y);
- IF a THEN
- cairo_pattern_add_color_stop_rgb(pat, 0.3, 0.2, 0.6, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 0.5, 1.0, 1.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 0.7, 1.0, 0.95, 0.7)
- ELSE
- cairo_pattern_add_color_stop_rgb(pat, 0.3, 1.0, 0.95, 0.7);
- cairo_pattern_add_color_stop_rgb(pat, 0.5, 1.0, 1.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 0.7, 0.2, 0.6, 1.0)
- END;
- cairo_set_source(cr, pat)
- END;
- cairo_rectangle(cr, x, y, 1.0, 1.0);
- cairo_fill(cr);
- IF a # b THEN
- cairo_pattern_destroy(pat)
- END
- END HBetween;
- (* A 1x1 tile with a vertical gradient between differing neighbours. *)
- PROCEDURE VBetween (cr: ADDRESS; x, y: REAL; a, b: BOOLEAN);
- VAR
- pat: ADDRESS;
- BEGIN
- IF a = b THEN
- SetOnColor(cr, a)
- ELSE
- pat := cairo_pattern_create_linear(x, y, x, y + 1.0);
- IF a THEN
- cairo_pattern_add_color_stop_rgb(pat, 0.3, 0.2, 0.6, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 0.5, 1.0, 1.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 0.7, 1.0, 0.95, 0.7)
- ELSE
- cairo_pattern_add_color_stop_rgb(pat, 0.3, 1.0, 0.95, 0.7);
- cairo_pattern_add_color_stop_rgb(pat, 0.5, 1.0, 1.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pat, 0.7, 0.2, 0.6, 1.0)
- END;
- cairo_set_source(cr, pat)
- END;
- cairo_rectangle(cr, x, y, 1.0, 1.0);
- cairo_fill(cr);
- IF a # b THEN
- cairo_pattern_destroy(pat)
- END
- END VBetween;
- PROCEDURE SnappingDraw (area: ADDRESS; cr: ADDRESS;
- width, height: INTEGER; data: ADDRESS);
- VAR
- cell, ox, oy, x, y: INTEGER;
- BEGIN
- (* 21 tiles plus 21 gaps make 43 units; snap to whole device pixels. *)
- cell := IMin(width, height) DIV 43;
- IF cell < 1 THEN cell := 1 END;
- ox := (width - 43 * cell) DIV 2;
- oy := (height - 43 * cell) DIV 2;
- cairo_save(cr);
- cairo_translate(cr, VAL(REAL, ox), VAL(REAL, oy));
- cairo_scale(cr, VAL(REAL, cell), VAL(REAL, cell));
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_rectangle(cr, 0.0, 0.0, 43.0, 43.0);
- cairo_fill(cr);
- (* tile centres at odd coordinates 1, 3, ..., 41 *)
- FOR y := 0 TO 20 DO
- FOR x := 0 TO 20 DO
- SetOnColor(cr, QrOn(x, y));
- cairo_rectangle(cr, VAL(REAL, 2 * x + 1), VAL(REAL, 2 * y + 1),
- 1.0, 1.0);
- cairo_fill(cr)
- END
- END;
- (* horizontal gaps between columns *)
- FOR y := 0 TO 20 DO
- FOR x := 0 TO 19 DO
- HBetween(cr, VAL(REAL, 2 * x + 2), VAL(REAL, 2 * y + 1),
- QrOn(x, y), QrOn(x + 1, y))
- END
- END;
- (* vertical gaps between rows *)
- FOR y := 0 TO 19 DO
- FOR x := 0 TO 20 DO
- VBetween(cr, VAL(REAL, 2 * x + 1), VAL(REAL, 2 * y + 2),
- QrOn(x, y), QrOn(x, y + 1))
- END
- END;
- cairo_restore(cr)
- END SnappingDraw;
- PROCEDURE DoSnapping (doWidget: ADDRESS) : ADDRESS;
- VAR
- da: ADDRESS;
- BEGIN
- IF snappingWindow = NIL THEN
- snappingWindow := gtk_window_new();
- gtk_window_set_title(snappingWindow, "Snapping");
- gtk_window_set_default_size(snappingWindow, 600, 400);
- da := gtk_drawing_area_new();
- gtk_window_set_child(snappingWindow, da);
- gtk_drawing_area_set_draw_func(da, ADR(SnappingDraw), NIL, NIL)
- END;
- IF gtk_widget_get_visible(snappingWindow) = 0 THEN
- gtk_widget_set_visible(snappingWindow, 1)
- ELSE
- gtk_window_destroy(snappingWindow);
- snappingWindow := NIL
- END;
- RETURN snappingWindow
- END DoSnapping;
- BEGIN
- drawingWindow := NIL;
- drawSurface := NIL;
- dragStartX := 0.0;
- dragStartY := 0.0;
- gesturesWindow := NIL;
- swipeX := 0.0;
- swipeY := 0.0;
- rotateDelta := 0.0;
- zoomScale := 1.0;
- longPressed := FALSE;
- hasRotate := FALSE;
- hasZoom := FALSE;
- maskWindow := NIL;
- maskScale := NIL;
- maskProgress := 0.5;
- snappingWindow := NIL;
- InitQrData
- END DemosCanvas.
|