diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 15:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 15:07:22 +0000 |
commit | f9d480cfe50ca1d7a0f0b5a2b8bb9932962bfbe7 (patch) | |
tree | ce9e8db2d4e8799780fa72ae8f1953039373e2ee /tests/interactive | |
parent | Initial commit. (diff) | |
download | gnome-shell-f9d480cfe50ca1d7a0f0b5a2b8bb9932962bfbe7.tar.xz gnome-shell-f9d480cfe50ca1d7a0f0b5a2b8bb9932962bfbe7.zip |
Adding upstream version 3.38.6.upstream/3.38.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | tests/interactive/background-repeat.js | 28 | ||||
-rw-r--r-- | tests/interactive/background-size.js | 115 | ||||
-rw-r--r-- | tests/interactive/border-radius.js | 61 | ||||
-rw-r--r-- | tests/interactive/border-width.js | 58 | ||||
-rw-r--r-- | tests/interactive/borders.js | 133 | ||||
-rw-r--r-- | tests/interactive/box-layout.js | 85 | ||||
-rw-r--r-- | tests/interactive/box-shadow-animated.js | 80 | ||||
-rw-r--r-- | tests/interactive/box-shadows.js | 56 | ||||
-rw-r--r-- | tests/interactive/calendar.js | 28 | ||||
-rw-r--r-- | tests/interactive/css-fonts.js | 40 | ||||
-rw-r--r-- | tests/interactive/entry.js | 57 | ||||
-rwxr-xr-x | tests/interactive/gapplication.js | 104 | ||||
-rw-r--r-- | tests/interactive/icons.js | 79 | ||||
-rw-r--r-- | tests/interactive/inline-style.js | 46 | ||||
-rw-r--r-- | tests/interactive/scroll-view-sizing.js | 395 | ||||
-rw-r--r-- | tests/interactive/scrolling.js | 51 | ||||
-rwxr-xr-x | tests/interactive/test-title.js | 37 | ||||
-rw-r--r-- | tests/interactive/transitions.js | 35 |
18 files changed, 1488 insertions, 0 deletions
diff --git a/tests/interactive/background-repeat.js b/tests/interactive/background-repeat.js new file mode 100644 index 0000000..1377f74 --- /dev/null +++ b/tests/interactive/background-repeat.js @@ -0,0 +1,28 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage({ width: 640, height: 480 }); + UI.init(stage); + + let vbox = new St.BoxLayout({ width: stage.width, + height: stage.height, + style: 'background: #ffee88;' }); + stage.add_actor(vbox); + + let scroll = new St.ScrollView(); + vbox.add(scroll, { expand: true }); + + let box = new St.BoxLayout({ vertical: true }); + scroll.add_actor(box); + + let contents = new St.Widget({ width: 1000, height: 1000, + style_class: 'background-image background-repeat' }); + box.add_actor(contents); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/background-size.js b/tests/interactive/background-size.js new file mode 100644 index 0000000..064bc9e --- /dev/null +++ b/tests/interactive/background-size.js @@ -0,0 +1,115 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Cogl, Clutter, Meta, St } = imports.gi; + + +function test() { + Meta.init(); + + let stage = Meta.get_backend().get_stage(); + UI.init(stage); + + let vbox = new St.BoxLayout({ style: 'background: #ffee88;' }); + vbox.add_constraint(new Clutter.BindConstraint({ source: stage, + coordinate: Clutter.BindCoordinate.SIZE })); + stage.add_actor(vbox); + + let scroll = new St.ScrollView(); + vbox.add(scroll, { expand: true }); + + vbox = new St.BoxLayout({ vertical: true, + style: 'padding: 10px;' + + 'spacing: 20px;' }); + scroll.add_actor(vbox); + + let tbox = null; + + function addTestCase(image, size, backgroundSize, useCairo) { + // Using a border in CSS forces cairo rendering. + // To get a border using cogl, we paint a border using + // paint signal hacks. + + let obin = new St.Bin(); + if (useCairo) + obin.style = 'border: 3px solid green;'; + else + obin.connect_after('paint', (actor, paintContext) => { + let framebuffer = paintContext.get_framebuffer(); + let coglContext = framebuffer.get_context(); + + let pipeline = new Cogl.Pipeline(coglContext); + pipeline.set_color4f(0, 1, 0, 1); + + let alloc = actor.get_allocation_box(); + let width = 3; + + // clockwise order + framebuffer.draw_rectangle(pipeline, + 0, 0, alloc.get_width(), width); + framebuffer.draw_rectangle(pipeline, + alloc.get_width() - width, width, + alloc.get_width(), alloc.get_height()); + framebuffer.draw_rectangle(pipeline, + 0, + alloc.get_height(), + alloc.get_width() - width, + alloc.get_height() - width); + framebuffer.draw_rectangle(pipeline, + 0, + alloc.get_height() - width, + width, + width); + }); + tbox.add(obin); + + let [width, height] = size; + let bin = new St.Bin({ style_class: 'background-image-' + image, + width: width, + height: height, + style: 'border: 1px solid transparent;' + + 'background-size: ' + backgroundSize + ';', + x_fill: true, + y_fill: true + }); + obin.set_child(bin); + + bin.set_child(new St.Label({ text: backgroundSize + (useCairo ? ' (cairo)' : ' (cogl)'), + style: 'font-size: 15px;' + + 'text-align: center;' + })); + } + + function addTestLine(image, size, useCairo) { + const backgroundSizes = ["auto", "contain", "cover", "200px 200px", "100px 100px", "100px 200px"]; + + let [width, height] = size; + vbox.add(new St.Label({ text: image + '.svg / ' + width + '×' + height, + style: 'font-size: 15px;' + + 'text-align: center;' + })); + + tbox = new St.BoxLayout({ style: 'spacing: 20px;' }); + vbox.add(tbox); + + for (let s of backgroundSizes) + addTestCase(image, size, s, false); + for (let s of backgroundSizes) + addTestCase(image, size, s, true); + } + + function addTestImage(image) { + const containerSizes = [[100, 100], [200, 200], [250, 250], [100, 250], [250, 100]]; + + for (let size of containerSizes) + addTestLine(image, size); + } + + addTestImage ('200-200'); + addTestImage ('200-100'); + addTestImage ('100-200'); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/border-radius.js b/tests/interactive/border-radius.js new file mode 100644 index 0000000..4d26518 --- /dev/null +++ b/tests/interactive/border-radius.js @@ -0,0 +1,61 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage({ width: 640, height: 480 }); + UI.init(stage); + + let vbox = new St.BoxLayout({ width: stage.width, + height: stage.height, + style: 'background: #ffee88;' }); + stage.add_actor(vbox); + + let scroll = new St.ScrollView(); + vbox.add(scroll, { expand: true }); + + let box = new St.BoxLayout({ vertical: true, + style: 'padding: 10px;' + + 'spacing: 20px;' }); + scroll.add_actor(box); + + function addTestCase(radii, useGradient) { + let background; + if (useGradient) + background = 'background-gradient-direction: vertical;' + + 'background-gradient-start: white;' + + 'background-gradient-end: gray;'; + else + background = 'background: white;'; + + box.add(new St.Label({ text: "border-radius: " + radii + ";", + style: 'border: 1px solid black; ' + + 'border-radius: ' + radii + ';' + + 'padding: 5px;' + background }), + { x_fill: false }); + } + + // uniform backgrounds + addTestCase(" 0px 5px 10px 15px", false); + addTestCase(" 5px 10px 15px 0px", false); + addTestCase("10px 15px 0px 5px", false); + addTestCase("15px 0px 5px 10px", false); + + // gradient backgrounds + addTestCase(" 0px 5px 10px 15px", true); + addTestCase(" 5px 10px 15px 0px", true); + addTestCase("10px 15px 0px 5px", true); + addTestCase("15px 0px 5px 10px", true); + + // border-radius reduction + // these should all take the cairo fallback, + // so don't bother testing w/ or w/out gradients. + addTestCase("200px 200px 200px 200px", false); + addTestCase("200px 200px 0px 200px", false); + addTestCase("999px 0px 999px 0px", false); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/border-width.js b/tests/interactive/border-width.js new file mode 100644 index 0000000..30c7575 --- /dev/null +++ b/tests/interactive/border-width.js @@ -0,0 +1,58 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage({ width: 640, height: 480 }); + UI.init(stage); + + let vbox = new St.BoxLayout({ width: stage.width, + height: stage.height, + style: 'padding: 10px; background: #ffee88;' + }); + stage.add_actor(vbox); + + let scroll = new St.ScrollView(); + vbox.add(scroll, { expand: true }); + + let box = new St.BoxLayout({ vertical: true, + style: 'spacing: 20px;' }); + scroll.add_actor(box); + + function addTestCase(borders, useGradient) { + let background; + if (useGradient) + background = 'background-gradient-direction: vertical;' + + 'background-gradient-start: white;' + + 'background-gradient-end: gray;'; + else + background = 'background: white;'; + + let border_style = "border-top: " + borders[St.Side.TOP] + " solid black;\n" + + "border-right: " + borders[St.Side.RIGHT] + " solid black;\n" + + "border-bottom: " + borders[St.Side.BOTTOM] + " solid black;\n" + + "border-left: " + borders[St.Side.LEFT] + " solid black;"; + box.add(new St.Label({ text: border_style, + style: border_style + + 'border-radius: 0px 5px 15px 25px;' + + 'padding: 5px;' + background }), + { x_fill: false }); + } + + // uniform backgrounds + addTestCase([" 0px", " 5px", "10px", "15px"], false); + addTestCase([" 5px", "10px", "15px", " 0px"], false); + addTestCase(["10px", "15px", " 0px", " 5px"], false); + addTestCase(["15px", " 0px", " 5px", "10px"], false); + + // gradient backgrounds + addTestCase([" 0px", " 5px", "10px", "15px"], true); + addTestCase([" 5px", "10px", "15px", " 0px"], true); + addTestCase(["10px", "15px", " 0px", " 5px"], true); + addTestCase(["15px", " 0px", " 5px", "10px"], true); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/borders.js b/tests/interactive/borders.js new file mode 100644 index 0000000..4812acb --- /dev/null +++ b/tests/interactive/borders.js @@ -0,0 +1,133 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage({ width: 640, height: 480 }); + UI.init(stage); + + let vbox = new St.BoxLayout({ width: stage.width, + height: stage.height, + style: 'background: #ffee88;' }); + stage.add_actor(vbox); + + let scroll = new St.ScrollView(); + vbox.add(scroll, { expand: true }); + + let box = new St.BoxLayout({ vertical: true, + style: 'padding: 10px;' + + 'spacing: 20px;' }); + scroll.add_actor(box); + + box.add(new St.Label({ text: "Hello World", + style: 'border: 1px solid black; ' + + 'padding: 5px;' })); + + box.add(new St.Label({ text: "Hello Round World", + style: 'border: 3px solid green; ' + + 'border-radius: 8px; ' + + 'padding: 5px;' })); + + box.add(new St.Label({ text: "Hello Background", + style: 'border: 3px solid green; ' + + 'border-radius: 8px; ' + + 'background: white; ' + + 'padding: 5px;' })); + + box.add(new St.Label({ text: "Hello Translucent Black Border", + style: 'border: 3px solid rgba(0, 0, 0, 0.4); ' + + 'background: white; ' })); + + box.add(new St.Label({ text: "Hello Translucent Background", + style: 'background: rgba(255, 255, 255, 0.3);' })); + + box.add(new St.Label({ text: "Border, Padding, Content: 20px" })); + + let b1 = new St.BoxLayout({ vertical: true, + style: 'border: 20px solid black; ' + + 'background: white; ' + + 'padding: 20px;' }); + box.add(b1); + + b1.add(new St.BoxLayout({ width: 20, height: 20, + style: 'background: black' })); + + box.add(new St.Label({ text: "Translucent big blue border, with rounding", + style: 'border: 20px solid rgba(0, 0, 255, 0.2); ' + + 'border-radius: 10px; ' + + 'background: white; ' + + 'padding: 10px;' })); + + box.add(new St.Label({ text: "Transparent border", + style: 'border: 20px solid transparent; ' + + 'background: white; ' + + 'padding: 10px;' })); + + box.add(new St.Label({ text: "Border Image", + style_class: "border-image", + style: "padding: 10px;" })); + + box.add(new St.Label({ text: "Border Image with Gradient", + style_class: 'border-image-with-background-gradient', + style: "padding: 10px;" + + 'background-gradient-direction: vertical;' })); + + box.add(new St.Label({ text: "Rounded, framed, shadowed gradients" })); + + let framedGradients = new St.BoxLayout({ vertical: false, + style: 'padding: 10px; spacing: 12px;' }); + box.add(framedGradients); + + function addGradientCase(direction, borderWidth, borderRadius, extra) { + let gradientBox = new St.BoxLayout({ style_class: 'background-gradient', + style: 'border: ' + borderWidth + 'px solid #8b0000;' + + 'border-radius: ' + borderRadius + 'px;' + + 'background-gradient-direction: ' + direction + ';' + + 'width: 32px;' + + 'height: 32px;' + + extra }); + framedGradients.add(gradientBox, { x_fill: false, y_fill: false } ); + } + + addGradientCase ('horizontal', 0, 5, 'box-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);'); + addGradientCase ('horizontal', 2, 5, 'box-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);'); + addGradientCase ('horizontal', 5, 2, 'box-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);'); + addGradientCase ('horizontal', 5, 20, 'box-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);'); + addGradientCase ('vertical', 0, 5, 'box-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);'); + addGradientCase ('vertical', 2, 5, 'box-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);'); + addGradientCase ('vertical', 5, 2, 'box-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);'); + addGradientCase ('vertical', 5, 20, 'box-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);'); + + box.add(new St.Label({ text: "Rounded, framed, shadowed images" })); + + let framedImages = new St.BoxLayout({ vertical: false, + style: 'padding: 10px; spacing: 6px;' }); + box.add(framedImages); + + function addBackgroundImageCase(borderWidth, borderRadius, width, height, extra) { + let imageBox = new St.BoxLayout({ style_class: 'background-image', + style: 'border: ' + borderWidth + 'px solid #8b8b8b;' + + 'border-radius: ' + borderRadius + 'px;' + + 'width: ' + width + 'px;' + + 'height: ' + height + 'px;' + + extra }); + framedImages.add(imageBox, { x_fill: false, y_fill: false } ); + } + + addBackgroundImageCase (0, 0, 32, 32, 'background-position: 2px 5px'); + addBackgroundImageCase (0, 0, 16, 16, '-st-background-image-shadow: 1px 1px 4px 0px rgba(0,0,0,0.5); background-color: rgba(0,0,0,0)'); + addBackgroundImageCase (0, 5, 32, 32, '-st-background-image-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);'); + addBackgroundImageCase (2, 5, 32, 32, '-st-background-image-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);'); + addBackgroundImageCase (5, 2, 32, 32, '-st-background-image-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);'); + addBackgroundImageCase (5, 20, 32, 32, '-st-background-image-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);'); + addBackgroundImageCase (0, 5, 48, 48, '-st-background-image-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);'); + addBackgroundImageCase (5, 5, 48, 48, '-st-background-image-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);'); + addBackgroundImageCase (0, 5, 64, 64, '-st-background-image-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);'); + addBackgroundImageCase (5, 5, 64, 64, '-st-background-image-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);'); + addBackgroundImageCase (0, 5, 32, 32, 'background-position: 2px 5px'); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/box-layout.js b/tests/interactive/box-layout.js new file mode 100644 index 0000000..bb9a5bb --- /dev/null +++ b/tests/interactive/box-layout.js @@ -0,0 +1,85 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage(); + UI.init(stage); + + let vbox = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height, + style: 'padding: 10px;' + + 'spacing: 10px;' }); + stage.add_actor(vbox); + + //////////////////////////////////////////////////////////////////////////////// + + let colored_boxes = new St.BoxLayout({ vertical: true, + width: 200, + height: 200, + style: 'border: 2px solid black;' }); + vbox.add(colored_boxes, { x_fill: false, + x_align: St.Align.MIDDLE }); + + let b2 = new St.BoxLayout({ style: 'border: 2px solid #666666' }); + colored_boxes.add(b2, { expand: true }); + + b2.add(new St.Label({ text: "Expand", + style: 'border: 1px solid #aaaaaa; ' + + 'background: #ffeecc' }), + { expand: true }); + b2.add(new St.Label({ text: "Expand\nNo Fill", + style: 'border: 1px solid #aaaaaa; ' + + 'background: #ccffaa' }), + { expand: true, + x_fill: false, + x_align: St.Align.MIDDLE, + y_fill: false, + y_align: St.Align.MIDDLE }); + + colored_boxes.add(new St.Label({ text: "Default", + style: 'border: 1px solid #aaaaaa; ' + + 'background: #cceeff' })); + + //////////////////////////////////////////////////////////////////////////////// + + function createCollapsableBox(width) { + let b = new St.BoxLayout({ width: width, + style: 'border: 1px solid black;' + + 'font: 13px Sans;' }); + b.add(new St.Label({ text: "Very Very Very Long", + style: 'background: #ffaacc;' + + 'padding: 5px; ' + + 'border: 1px solid #666666;' }), + { expand: true }); + b.add(new St.Label({ text: "Very Very Long", + style: 'background: #ffeecc; ' + + 'padding: 5px; ' + + 'border: 1px solid #666666;' }), + { expand: true }); + b.add(new St.Label({ text: "Very Long", + style: 'background: #ccffaa; ' + + 'padding: 5px; ' + + 'border: 1px solid #666666;' }), + { expand: true }); + b.add(new St.Label({ text: "Short", + style: 'background: #cceeff; ' + + 'padding: 5px; ' + + 'border: 1px solid #666666;' }), + { expand: true }); + + return b; + } + + for (let width = 200; width <= 500; width += 60 ) { + vbox.add(createCollapsableBox (width), + { x_fill: false, + x_align: St.Align.MIDDLE }); + } + + UI.main(stage); +} +test(); diff --git a/tests/interactive/box-shadow-animated.js b/tests/interactive/box-shadow-animated.js new file mode 100644 index 0000000..cf117a7 --- /dev/null +++ b/tests/interactive/box-shadow-animated.js @@ -0,0 +1,80 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, GLib, St } = imports.gi; + +const DELAY = 2000; + +function resize_animated(label) { + if (label.width == 100) { + label.save_easing_state(); + label.set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD); + label.set_easing_duration(DELAY - 50); + label.set_size(500, 500); + label.restore_easing_state(); + } else { + label.save_easing_state(); + label.set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD); + label.set_easing_duration(DELAY - 50); + label.set_size(100, 100); + label.restore_easing_state(); + } +} + +function get_css_style(shadow_style) +{ + return 'border: 20px solid black;' + + 'border-radius: 20px;' + + 'background-color: white; ' + + 'padding: 5px;' + shadow_style; +} + +function test() { + let stage = new Clutter.Stage({ width: 1000, height: 600 }); + UI.init(stage); + + let iter = 0; + let shadowStyles = [ 'box-shadow: 3px 50px 0px 4px rgba(0,0,0,0.5);', + 'box-shadow: 3px 4px 10px 4px rgba(0,0,0,0.5);', + 'box-shadow: 0px 50px 0px 0px rgba(0,0,0,0.5);', + 'box-shadow: 100px 100px 20px 4px rgba(0,0,0,0.5);']; + let label1 = new St.Label({ style: get_css_style(shadowStyles[iter]), + text: shadowStyles[iter], + x: 20, + y: 20, + width: 100, + height: 100 + }); + stage.add_actor(label1); + let label2 = new St.Label({ style: get_css_style(shadowStyles[iter]), + text: shadowStyles[iter], + x: 500, + y: 20, + width: 100, + height: 100 + }); + stage.add_actor(label2); + + resize_animated(label1); + resize_animated(label2); + GLib.timeout_add(GLib.PRIORITY_DEFAULT, DELAY, () => { + log(label1 + label1.get_size()); + resize_animated(label1); + resize_animated(label2); + return true; + }); + + GLib.timeout_add(GLib.PRIORITY_DEFAULT, 2 * DELAY, () => { + iter += 1; + iter %= shadowStyles.length; + label1.set_style(get_css_style(shadowStyles[iter])); + label1.set_text(shadowStyles[iter]); + label2.set_style(get_css_style(shadowStyles[iter])); + label2.set_text(shadowStyles[iter]); + return true; + }); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/box-shadows.js b/tests/interactive/box-shadows.js new file mode 100644 index 0000000..c9c677c --- /dev/null +++ b/tests/interactive/box-shadows.js @@ -0,0 +1,56 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage({ width: 640, height: 480 }); + UI.init(stage); + + let vbox = new St.BoxLayout({ width: stage.width, + height: stage.height, + style: 'background: #ffee88;' }); + stage.add_actor(vbox); + + let scroll = new St.ScrollView(); + vbox.add(scroll, { expand: true }); + + let box = new St.BoxLayout({ vertical: true, + style: 'padding: 10px;' + + 'spacing: 20px;' }); + scroll.add_actor(box); + + + function addTestCase(inset, offsetX, offsetY, blur, spread) { + let shadowStyle = 'box-shadow: ' + (inset ? 'inset ' : '') + + offsetX + 'px ' + offsetY + 'px ' + blur + 'px ' + + (spread > 0 ? (' ' + spread + 'px ') : '') + + 'rgba(0,0,0,0.5);'; + let label = new St.Label({ style: 'border: 4px solid black;' + + 'border-radius: 5px;' + + 'background-color: white; ' + + 'padding: 5px;' + + shadowStyle, + text: shadowStyle }); + box.add(label, { x_fill: false, y_fill: false } ); + } + + addTestCase (false, 3, 4, 0, 0); + addTestCase (false, 3, 4, 0, 4); + addTestCase (false, 3, 4, 4, 0); + addTestCase (false, 3, 4, 4, 4); + addTestCase (false, -3, -4, 4, 0); + addTestCase (false, 0, 0, 0, 4); + addTestCase (false, 0, 0, 4, 0); + addTestCase (true, 3, 4, 0, 0); + addTestCase (true, 3, 4, 0, 4); + addTestCase (true, 3, 4, 4, 0); + addTestCase (true, 3, 4, 4, 4); + addTestCase (true, -3, -4, 4, 0); + addTestCase (true, 0, 0, 0, 4); + addTestCase (true, 0, 0, 4, 0); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/calendar.js b/tests/interactive/calendar.js new file mode 100644 index 0000000..d1d435a --- /dev/null +++ b/tests/interactive/calendar.js @@ -0,0 +1,28 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage({ width: 400, height: 400 }); + UI.init(stage); + + let vbox = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height, + style: 'padding: 10px; spacing: 10px; font: 15px sans-serif;' }); + stage.add_actor(vbox); + + // Calendar can only be imported after Environment.init() + const Calendar = imports.ui.calendar; + let calendar = new Calendar.Calendar(); + vbox.add(calendar, + { expand: true, + x_fill: false, x_align: St.Align.MIDDLE, + y_fill: false, y_align: St.Align.START }); + calendar.setEventSource(new Calendar.EmptyEventSource()); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/css-fonts.js b/tests/interactive/css-fonts.js new file mode 100644 index 0000000..a257693 --- /dev/null +++ b/tests/interactive/css-fonts.js @@ -0,0 +1,40 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage(); + UI.init(stage); + + let b = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height }); + stage.add_actor(b); + + let t; + + t = new St.Label({ "text": "Bold", style_class: "bold" }); + b.add(t); + t = new St.Label({ "text": "Monospace", style_class: "monospace" }); + b.add(t); + t = new St.Label({ "text": "Italic", style_class: "italic" }); + b.add(t); + t = new St.Label({ "text": "Bold Italic", style_class: "bold italic" }); + b.add(t); + t = new St.Label({ "text": "Big Italic", style_class: "big italic" }); + b.add(t); + t = new St.Label({ "text": "Big Bold", style_class: "big bold" }); + b.add(t); + + let b2 = new St.BoxLayout({ vertical: true, style_class: "monospace" }); + b.add(b2); + t = new St.Label({ "text": "Big Monospace", style_class: "big" }); + b2.add(t); + t = new St.Label({ "text": "Italic Monospace", style_class: "italic" }); + b2.add(t); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/entry.js b/tests/interactive/entry.js new file mode 100644 index 0000000..9ae0106 --- /dev/null +++ b/tests/interactive/entry.js @@ -0,0 +1,57 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, GLib, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage({ width: 400, height: 400 }); + UI.init(stage); + + let vbox = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height, + style: 'padding: 10px; spacing: 10px; font: 32px sans-serif;' }); + stage.add_actor(vbox); + + let entry = new St.Entry({ style: 'border: 1px solid black; text-shadow: 0 2px red;', + text: 'Example text' }); + vbox.add(entry, + { expand: true, + y_fill: false, y_align: St.Align.MIDDLE }); + entry.grab_key_focus(); + + let entryTextHint = new St.Entry({ style: 'border: 1px solid black; text-shadow: 0 2px red;', + hint_text: 'Hint text' }); + vbox.add(entryTextHint, + { expand: true, + y_fill: false, y_align: St.Align.MIDDLE }); + + let hintActor = new St.Label({ text: 'Hint actor' }); + let entryHintActor = new St.Entry({ style: 'border: 1px solid black; text-shadow: 0 2px red;', + hint_actor: hintActor }); + vbox.add(entryHintActor, + { expand: true, + y_fill: false, y_align: St.Align.MIDDLE }); + + let hintActor2 = new St.Label({ text: 'Hint both (actor)' }); + let entryHintBoth = new St.Entry({ style: 'border: 1px solid black; text-shadow: 0 2px red;', + hint_actor: hintActor2 }); + let idx = 0; + GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, function() { + idx++; + + if (idx % 2 == 0) + entryHintBoth.hint_actor = hintActor2; + else + entryHintBoth.hint_text = 'Hint both (text)'; + + return true; + }); + vbox.add(entryHintBoth, + { expand: true, + y_fill: false, y_align: St.Align.MIDDLE }); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/gapplication.js b/tests/interactive/gapplication.js new file mode 100755 index 0000000..ec38b80 --- /dev/null +++ b/tests/interactive/gapplication.js @@ -0,0 +1,104 @@ +#!/usr/bin/env gjs +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +imports.gi.versions = { Gdk: '3.0', Gtk: '3.0' }; +const { Gdk, Gio, GLib, Gtk } = imports.gi; + +function do_action(action, parameter) { + print ("Action '" + action.name + "' invoked"); +} + +function do_action_param(action, parameter) { + print ("Action '" + action.name + "' invoked with parameter " + parameter.print(true)); +} + +function do_action_toggle(action) { + action.set_state(GLib.Variant.new('b', !action.state.deep_unpack())); + print ("Toggled"); +} + +function do_action_state_change(action) { + print ("Action '" + action.name + "' has now state " + action.state.print(true)); +} + +function main() { + Gtk.init(null); + Gdk.set_program_class('test-gjsgapp'); + + let app = new Gtk.Application({ application_id: 'org.gnome.Shell.GtkApplicationTest' }); + app.connect('activate', () => { + print ("Activated"); + }); + + let action = new Gio.SimpleAction({ name: 'one' }); + action.connect('activate', do_action); + app.add_action(action); + + action = new Gio.SimpleAction({ name: 'two' }); + action.connect('activate', do_action); + app.add_action(action); + + action = new Gio.SimpleAction({ name: 'toggle', state: GLib.Variant.new('b', false) }); + action.connect('activate', do_action_toggle); + action.connect('notify::state', do_action_state_change); + app.add_action(action); + + action = new Gio.SimpleAction({ name: 'disable', enabled: false }); + action.set_enabled(false); + action.connect('activate', do_action); + app.add_action(action); + + action = new Gio.SimpleAction({ name: 'parameter-int', parameter_type: GLib.VariantType.new('u') }); + action.connect('activate', do_action_param); + app.add_action(action); + + action = new Gio.SimpleAction({ name: 'parameter-string', parameter_type: GLib.VariantType.new('s') }); + action.connect('activate', do_action_param); + app.add_action(action); + + let menu = new Gio.Menu(); + menu.append('An action', 'app.one'); + + let section = new Gio.Menu(); + section.append('Another action', 'app.two'); + section.append('Same as above', 'app.two'); + menu.append_section(null, section); + + // another section, to check separators + section = new Gio.Menu(); + section.append('Checkbox', 'app.toggle'); + section.append('Disabled', 'app.disable'); + section.append('Missing Action', 'app.no-action'); + menu.append_section('Subsection', section); + + // empty sections or submenus should be invisible + menu.append_section('Empty section', new Gio.Menu()); + menu.append_submenu('Empty submenu', new Gio.Menu()); + + let submenu = new Gio.Menu(); + submenu.append('Open c:\\', 'app.parameter-string::c:\\'); + submenu.append('Open /home', 'app.parameter-string::/home'); + menu.append_submenu('Recent files', submenu); + + let item = Gio.MenuItem.new('Say 42', null); + item.set_action_and_target_value('app.parameter-int', GLib.Variant.new('u', 42)); + menu.append_item(item); + + item = Gio.MenuItem.new('Say 43', null); + item.set_action_and_target_value('app.parameter-int', GLib.Variant.new('u', 43)); + menu.append_item(item); + + let window = null; + + app.connect_after('startup', app => { + app.set_app_menu(menu); + window = new Gtk.ApplicationWindow({ title: "Test Application", application: app }); + }); + app.connect('activate', app => { + window.present(); + }); + + app.run(null); +} + +main(); diff --git a/tests/interactive/icons.js b/tests/interactive/icons.js new file mode 100644 index 0000000..65b7f65 --- /dev/null +++ b/tests/interactive/icons.js @@ -0,0 +1,79 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage(); + UI.init(stage); + + let b = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height }); + stage.add_actor(b); + + function addTest(label, icon_props) { + if (b.get_children().length > 0) + b.add (new St.BoxLayout({ style: 'background: #cccccc; border: 10px transparent white; height: 1px; ' })); + + let hb = new St.BoxLayout({ vertical: false, + style: 'spacing: 10px;' }); + + hb.add(new St.Label({ text: label }), { y_fill: false }); + hb.add(new St.Icon(icon_props)); + + b.add(hb); + } + + addTest("Symbolic", + { icon_name: 'battery-full-symbolic', + icon_size: 48 }); + addTest("Full color", + { icon_name: 'battery-full', + icon_size: 48 }); + addTest("Default size", + { icon_name: 'battery-full-symbolic' }); + addTest("Size set by property", + { icon_name: 'battery-full-symbolic', + icon_size: 32 }); + addTest("Size set by style", + { icon_name: 'battery-full-symbolic', + style: 'icon-size: 1em;' }); + addTest("16px icon in 48px icon widget", + { icon_name: 'battery-full-symbolic', + style: 'icon-size: 16px; width: 48px; height: 48px; border: 1px solid black;' }); + + function iconRow(icons, box_style) { + let hb = new St.BoxLayout({ vertical: false, style: box_style }); + + for (let iconName of icons) { + hb.add(new St.Icon({ icon_name: iconName, + icon_size: 48 })); + } + + b.add(hb); + } + + let normalCss = 'background: white; color: black; padding: 10px 10px;'; + let reversedCss = 'background: black; color: white; warning-color: #ffcc00; error-color: #ff0000; padding: 10px 10px;'; + + let batteryIcons = ['battery-full-charging-symbolic', + 'battery-full-symbolic', + 'battery-good-symbolic', + 'battery-low-symbolic', + 'battery-caution-symbolic' ]; + + let volumeIcons = ['audio-volume-high-symbolic', + 'audio-volume-medium-symbolic', + 'audio-volume-low-symbolic', + 'audio-volume-muted-symbolic' ]; + + iconRow(batteryIcons, normalCss); + iconRow(batteryIcons, reversedCss); + iconRow(volumeIcons, normalCss); + iconRow(volumeIcons, reversedCss); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/inline-style.js b/tests/interactive/inline-style.js new file mode 100644 index 0000000..3952c3a --- /dev/null +++ b/tests/interactive/inline-style.js @@ -0,0 +1,46 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage(); + UI.init(stage); + + let vbox = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height }); + stage.add_actor(vbox); + + let hbox = new St.BoxLayout({ style: 'spacing: 12px;' }); + vbox.add(hbox); + + let text = new St.Label({ text: "Styled Text" }); + vbox.add (text); + + let size = 24; + function update_size() { + text.style = 'font-size: ' + size + 'pt'; + } + update_size(); + + let button; + + button = new St.Button ({ label: 'Smaller', style_class: 'push-button' }); + hbox.add (button); + button.connect('clicked', () => { + size /= 1.2; + update_size (); + }); + + button = new St.Button ({ label: 'Bigger', style_class: 'push-button' }); + hbox.add (button); + button.connect('clicked', () => { + size *= 1.2; + update_size (); + }); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/scroll-view-sizing.js b/tests/interactive/scroll-view-sizing.js new file mode 100644 index 0000000..a6c682e --- /dev/null +++ b/tests/interactive/scroll-view-sizing.js @@ -0,0 +1,395 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, GObject, Gtk, Shell, St } = imports.gi; + +// This is an interactive test of the sizing behavior of StScrollView. It +// may be interesting in the future to split out the two classes at the +// top into utility classes for testing the sizing behavior of other +// containers and actors. + +/****************************************************************************/ + +// FlowedBoxes: This is a simple actor that demonstrates an interesting +// height-for-width behavior. A set of boxes of different sizes are line-wrapped +// horizontally with the minimum horizontal size being determined by the +// largest box. It would be easy to extend this to allow doing vertical +// wrapping instead, if you wanted to see just how badly our width-for-height +// implementation is or work on fixing it. + +const BOX_HEIGHT = 20; +const BOX_WIDTHS = [ + 10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40, + 10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40, + 10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40, + 10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40, +]; + +const SPACING = 10; + +var FlowedBoxes = GObject.registerClass( +class FlowedBoxes extends St.Widget { + _init() { + super._init(); + + for (let i = 0; i < BOX_WIDTHS.length; i++) { + let child = new St.Bin({ width: BOX_WIDTHS[i], height: BOX_HEIGHT, + style: 'border: 1px solid #444444; background: #00aa44' }); + this.add_actor(child); + } + } + + vfunc_get_preferred_width(forHeight) { + let children = this.get_children(); + + let maxMinWidth = 0; + let totalNaturalWidth = 0; + + for (let i = 0; i < children.length; i++) { + let child = children[i]; + let [minWidth, naturalWidth] = child.get_preferred_width(-1); + maxMinWidth = Math.max(maxMinWidth, minWidth); + if (i != 0) + totalNaturalWidth += SPACING; + totalNaturalWidth += naturalWidth; + } + + return [maxMinWidth, totalNaturalWidth]; + } + + _layoutChildren(forWidth, callback) { + let children = this.get_children(); + + let x = 0; + let y = 0; + for (let i = 0; i < children.length; i++) { + let child = children[i]; + let [minWidth, naturalWidth] = child.get_preferred_width(-1); + let [minHeight, naturalHeight] = child.get_preferred_height(naturalWidth); + + let x1 = x; + if (x != 0) + x1 += SPACING; + let x2 = x1 + naturalWidth; + + if (x2 > forWidth) { + if (x > 0) { + x1 = 0; + y += BOX_HEIGHT + SPACING; + } + + x2 = naturalWidth; + } + + callback(child, x1, y, x2, y + naturalHeight); + x = x2; + } + + } + + vfunc_get_preferred_height(forWidth) { + let height = 0; + this._layoutChildren(forWidth, + function(child, x1, y1, x2, y2) { + height = Math.max(height, y2); + }); + + return [height, height]; + } + + vfunc_allocate(box) { + this.set_allocation(box); + + this._layoutChildren(box.x2 - box.x1, + function(child, x1, y1, x2, y2) { + child.allocate(new Clutter.ActorBox({ x1: x1, y1: y1, x2: x2, y2: y2 })); + }); + } +}); + +/****************************************************************************/ + +// SizingIllustrator: this is a container that allows interactively exploring +// the sizing behavior of the child. Lines are drawn to indicate the minimum +// and natural size of the child, and a drag handle allows the user to resize +// the child interactively and see how that affects it. +// +// This is currently only written for the case where the child is height-for-width + +var SizingIllustrator = GObject.registerClass( +class SizingIllustrator extends St.Widget { + _init() { + super._init(); + + this.minWidthLine = new St.Bin({ style: 'background: red' }); + this.add_actor(this.minWidthLine); + this.minHeightLine = new St.Bin({ style: 'background: red' }); + this.add_actor(this.minHeightLine); + + this.naturalWidthLine = new St.Bin({ style: 'background: #4444ff' }); + this.add_actor(this.naturalWidthLine); + this.naturalHeightLine = new St.Bin({ style: 'background: #4444ff' }); + this.add_actor(this.naturalHeightLine); + + this.currentWidthLine = new St.Bin({ style: 'background: #aaaaaa' }); + this.add_actor(this.currentWidthLine); + this.currentHeightLine = new St.Bin({ style: 'background: #aaaaaa' }); + this.add_actor(this.currentHeightLine); + + this.handle = new St.Bin({ style: 'background: yellow; border: 1px solid black;', + reactive: true }); + this.handle.connect('button-press-event', this._handlePressed.bind(this)); + this.handle.connect('button-release-event', this._handleReleased.bind(this)); + this.handle.connect('motion-event', this._handleMotion.bind(this)); + this.add_actor(this.handle); + + this._inDrag = false; + + this.width = 300; + this.height = 300; + } + + add(child) { + this.child = child; + this.add_child(child); + this.set_child_below_sibling(child, null); + } + + vfunc_get_preferred_width(forHeight) { + let children = this.get_children(); + for (let i = 0; i < children.length; i++) { + let child = children[i]; + let [minWidth, naturalWidth] = child.get_preferred_width(-1); + if (child == this.child) { + this.minWidth = minWidth; + this.naturalWidth = naturalWidth; + } + } + + return [0, 400]; + } + + vfunc_get_preferred_height(forWidth) { + let children = this.get_children(); + for (let i = 0; i < children.length; i++) { + let child = children[i]; + if (child == this.child) { + [this.minHeight, this.naturalHeight] = child.get_preferred_height(this.width); + } else { + let [minWidth, naturalWidth] = child.get_preferred_height(naturalWidth); + } + } + + return [0, 400]; + } + + vfunc_allocate(box) { + this.set_allocation(box); + + box = this.get_theme_node().get_content_box(box); + + let allocWidth = box.x2 - box.x1; + let allocHeight = box.y2 - box.y1; + + function alloc(child, x1, y1, x2, y2) { + child.allocate(new Clutter.ActorBox({ x1: x1, y1: y1, x2: x2, y2: y2 })); + } + + alloc(this.child, 0, 0, this.width, this.height); + alloc(this.minWidthLine, this.minWidth, 0, this.minWidth + 1, allocHeight); + alloc(this.naturalWidthLine, this.naturalWidth, 0, this.naturalWidth + 1, allocHeight); + alloc(this.currentWidthLine, this.width, 0, this.width + 1, allocHeight); + alloc(this.minHeightLine, 0, this.minHeight, allocWidth, this.minHeight + 1); + alloc(this.naturalHeightLine, 0, this.naturalHeight, allocWidth, this.naturalHeight + 1); + alloc(this.currentHeightLine, 0, this.height, allocWidth, this.height + 1); + alloc(this.handle, this.width, this.height, this.width + 10, this.height + 10); + } + + _handlePressed(handle, event) { + if (event.get_button() == 1) { + this._inDrag = true; + let [handleX, handleY] = handle.get_transformed_position(); + let [x, y] = event.get_coords(); + this._dragX = x - handleX; + this._dragY = y - handleY; + } + } + + _handleReleased(handle, event) { + if (event.get_button() == 1) { + this._inDrag = false; + } + } + + _handleMotion(handle, event) { + if (this._inDrag) { + let [x, y] = event.get_coords(); + let [actorX, actorY] = this.get_transformed_position(); + this.width = x - this._dragX - actorX; + this.height = y - this._dragY - actorY; + this.queue_relayout(); + } + } +}); + +/****************************************************************************/ + +function test() { + let stage = new Clutter.Stage({ width: 600, height: 600 }); + UI.init(stage); + + let mainBox = new St.BoxLayout({ width: stage.width, + height: stage.height, + vertical: true, + style: 'padding: 10px;' + + 'spacing: 5px;' + + 'font: 16px sans-serif;' + + 'background: black;' + + 'color: white;' }); + stage.add_actor(mainBox); + + const DOCS = 'Red lines represent minimum size, blue lines natural size. Drag yellow handle to resize ScrollView. Click on options to change.'; + + let docsLabel = new St.Label({ text: DOCS }); + docsLabel.clutter_text.line_wrap = true; + mainBox.add(docsLabel); + + let bin = new St.Bin({ x_fill: true, y_fill: true, style: 'border: 2px solid #666666;' }); + mainBox.add(bin, { x_fill: true, y_fill: true, expand: true }); + + let illustrator = new SizingIllustrator(); + bin.add_actor(illustrator); + + let scrollView = new St.ScrollView(); + illustrator.add(scrollView); + + let box = new St.BoxLayout({ vertical: true }); + scrollView.add_actor(box); + + let flowedBoxes = new FlowedBoxes(); + box.add(flowedBoxes, { expand: false, x_fill: true, y_fill: true }); + + let policyBox = new St.BoxLayout({ vertical: false }); + mainBox.add(policyBox); + + policyBox.add(new St.Label({ text: 'Horizontal Policy: ' })); + let hpolicy = new St.Button({ label: 'AUTOMATIC', style: 'text-decoration: underline; color: #4444ff;' }); + policyBox.add(hpolicy); + + let spacer = new St.Bin(); + policyBox.add(spacer, { expand: true }); + + policyBox.add(new St.Label({ text: 'Vertical Policy: '})); + let vpolicy = new St.Button({ label: 'AUTOMATIC', style: 'text-decoration: underline; color: #4444ff;' }); + policyBox.add(vpolicy); + + function togglePolicy(button) { + switch(button.label) { + case 'AUTOMATIC': + button.label = 'ALWAYS'; + break; + case 'ALWAYS': + button.label = 'NEVER'; + break; + case 'NEVER': + button.label = 'EXTERNAL'; + break; + case 'EXTERNAL': + button.label = 'AUTOMATIC'; + break; + } + scrollView.set_policy(Gtk.PolicyType[hpolicy.label], Gtk.PolicyType[vpolicy.label]); + } + + hpolicy.connect('clicked', () => { togglePolicy(hpolicy); }); + vpolicy.connect('clicked', () => { togglePolicy(vpolicy); }); + + let fadeBox = new St.BoxLayout({ vertical: false }); + mainBox.add(fadeBox); + + spacer = new St.Bin(); + fadeBox.add(spacer, { expand: true }); + + fadeBox.add(new St.Label({ text: 'Padding: '})); + let paddingButton = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;padding-right:3px;' }); + fadeBox.add(paddingButton); + + fadeBox.add(new St.Label({ text: 'Borders: '})); + let borderButton = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;padding-right:3px;' }); + fadeBox.add(borderButton); + + fadeBox.add(new St.Label({ text: 'Vertical Fade: '})); + let vfade = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' }); + fadeBox.add(vfade); + + fadeBox.add(new St.Label({ text: 'Overlay scrollbars: '})); + let overlay = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' }); + fadeBox.add(overlay); + + function togglePadding(button) { + switch(button.label) { + case 'No': + button.label = 'Yes'; + break; + case 'Yes': + button.label = 'No'; + break; + } + if (scrollView.style == null) + scrollView.style = (button.label == 'Yes' ? 'padding: 10px;' : 'padding: 0;'); + else + scrollView.style += (button.label == 'Yes' ? 'padding: 10px;' : 'padding: 0;'); + } + + paddingButton.connect('clicked', () => { togglePadding(paddingButton); }); + + function toggleBorders(button) { + switch(button.label) { + case 'No': + button.label = 'Yes'; + break; + case 'Yes': + button.label = 'No'; + break; + } + if (scrollView.style == null) + scrollView.style = (button.label == 'Yes' ? 'border: 2px solid red;' : 'border: 0;'); + else + scrollView.style += (button.label == 'Yes' ? 'border: 2px solid red;' : 'border: 0;'); + } + + borderButton.connect('clicked', () => { toggleBorders(borderButton); }); + + function toggleFade(button) { + switch(button.label) { + case 'No': + button.label = 'Yes'; + break; + case 'Yes': + button.label = 'No'; + break; + } + scrollView.set_style_class_name(button.label == 'Yes' ? 'vfade' : ''); + } + + vfade.connect('clicked', () => { toggleFade(vfade); }); + toggleFade(vfade); + + function toggleOverlay(button) { + switch(button.label) { + case 'No': + button.label = 'Yes'; + break; + case 'Yes': + button.label = 'No'; + break; + } + scrollView.overlay_scrollbars = (button.label == 'Yes'); + } + + overlay.connect('clicked', () => { toggleOverlay(overlay); }); + + UI.main(stage); +} +test(); diff --git a/tests/interactive/scrolling.js b/tests/interactive/scrolling.js new file mode 100644 index 0000000..91951ce --- /dev/null +++ b/tests/interactive/scrolling.js @@ -0,0 +1,51 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, Gtk, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage(); + UI.init(stage); + + let vbox = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height, + style: "padding: 10px;" }); + stage.add_actor(vbox); + + let toggle = new St.Button({ label: 'Horizontal Scrolling', + toggle_mode: true }); + vbox.add(toggle); + + let v = new St.ScrollView(); + vbox.add(v, { expand: true }); + + toggle.connect('notify::checked', () => { + v.set_policy(toggle.checked ? Gtk.PolicyType.AUTOMATIC + : Gtk.PolicyType.NEVER, + Gtk.PolicyType.AUTOMATIC); + }); + + let b = new St.BoxLayout({ vertical: true, + style: "border: 2px solid #880000; border-radius: 10px; padding: 0px 5px;" }); + v.add_actor(b); + + let cc_a = "a".charCodeAt(0); + let s = ""; + for (let i = 0; i < 26 * 3; i++) { + s += String.fromCharCode(cc_a + i % 26); + + let t = new St.Label({ text: s, + reactive: true }); + let line = i + 1; + t.connect('button-press-event', + function() { + log("Click on line " + line); + }); + b.add(t); + } + + UI.main(stage); +} +test(); diff --git a/tests/interactive/test-title.js b/tests/interactive/test-title.js new file mode 100755 index 0000000..0a468dd --- /dev/null +++ b/tests/interactive/test-title.js @@ -0,0 +1,37 @@ +#!/usr/bin/env gjs + +imports.gi.versions.Gtk = '3.0'; + +const { GLib, Gtk } = imports.gi; + +function nextTitle() { + let length = Math.random() * 20; + let str = ''; + + for (let i = 0; i < length; i++) { + // 97 == 'a' + str += String.fromCharCode(97 + Math.random() * 26); + } + + return str; +} + +function main() { + Gtk.init(null); + + let win = new Gtk.Window({ title: nextTitle() }); + win.connect('destroy', () => { + Gtk.main_quit(); + }); + win.present(); + + GLib.timeout_add(GLib.PRIORITY_DEFAULT, 5000, function() { + win.title = nextTitle(); + return true; + }); + + Gtk.main(); +} + +main(); + diff --git a/tests/interactive/transitions.js b/tests/interactive/transitions.js new file mode 100644 index 0000000..7b2eac1 --- /dev/null +++ b/tests/interactive/transitions.js @@ -0,0 +1,35 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const UI = imports.testcommon.ui; + +const { Clutter, St } = imports.gi; + +function test() { + let stage = new Clutter.Stage(); + UI.init(stage); + + let hbox = new St.BoxLayout({ name: 'transition-container', + reactive: true, + track_hover: true, + width: stage.width, + height: stage.height, + style: 'padding: 10px;' + + 'spacing: 10px;' }); + stage.add_actor(hbox); + + for (let i = 0; i < 5; i ++) { + let label = new St.Label({ text: (i+1).toString(), + name: "label" + i, + style_class: 'transition-label', + reactive: true, + track_hover: true }); + + hbox.add(label, { x_fill: false, + y_fill: false }); + } + + //////////////////////////////////////////////////////////////////////////////// + + UI.main(stage); +} +test(); |