<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2001/XInclude" type="guide" style="task" id="scale.js" xml:lang="sv">
  <info>
  <title type="text">Scale (Javascript)</title>
    <link type="guide" xref="beginner.js#entry"/>
    <revision version="0.1" date="2012-06-20" status="draft"/>

    <credit type="author copyright">
      <name>Taryn Fox</name>
      <email its:translate="no">jewelfox@fursona.net</email>
      <years>2012</years>
    </credit>

    <desc>Ett skjutreglage som motsvarar ett numeriskt värde</desc>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Sebastian Rasmussen</mal:name>
      <mal:email>sebras@gmail.com</mal:email>
      <mal:years>2019</mal:years>
    </mal:credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Anders Jonsson</mal:name>
      <mal:email>anders.jonsson@norsjovallen.se</mal:email>
      <mal:years>2021</mal:years>
    </mal:credit>
  </info>

  <title>Scale</title>
  <media type="image" mime="image/png" src="media/scalepenguins.png"/>
  <p>A Scale is a horizontal or vertical slider, that represents a value inside a numerical range. When you create a new Scale, you set what its default position is, what the numbers at the top and bottom of the range are, and things like how much it moves up or down when you click on the Scale to either side of the knob. To keep from having to type all that in every time you create a new Scale, you can create an object called an Adjustment which keeps track of all that, then tell each new Scale to use that Adjustment.</p>
  <p>This scale is a simple widget that lets you adjust the size of an iceberg that penguins live on. The number of penguins on the iceberg is the product of the values of the two sliders. Try playing with them and seeing what happens.</p>
    <links type="section"/>

  <section id="imports">
    <title>Bibliotek att importera</title>
    <code mime="application/javascript">
#!/usr/bin/gjs

const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
</code>
    <p>Detta är biblioteken som vi behöver importera för att detta program ska köras. Kom ihåg att raden som säger till GNOME att vi använder Gjs alltid behöver vara först.</p>
    </section>

  <section id="applicationwindow">
    <title>Skapa programfönstret</title>
    <code mime="application/javascript">
const ScaleExample = new Lang.Class({
    Name: 'Scale-exempel',

    // Skapa programmet i sig
    _init: function() {
        this.application = new Gtk.Application({
            application_id: 'org.example.jsscale'
        });

    // Anslut ”activate”- och ”startup”-signaler till återanropsfunktionerna
    this.application.connect('activate', Lang.bind(this, this._onActivate));
    this.application.connect('startup', Lang.bind(this, this._onStartup));
    },

    // Återanropsfunktion för ”activate”-signal, visar fönstret när den aktiveras
    _onActivate: function() {
        this._window.present();
    },

    // Återanropsfunktion för ”startup”-signal bygger användargränssnittet
    _onStartup: function() {
        this._buildUI ();
    },
</code>
    <p>All kod för detta exempel hamnar i klassen ScaleExample. Koden ovan skapar en <link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Gtk.Application</link> att ha våra komponenter och fönstret i.</p>
    <code mime="application/javascript">
    // Bygg programmets användargränssnitt
    _buildUI: function() {

        // Skapa programfönstret
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            border_width: 20,
            title: "Fåglar på ett isflak"});
</code>
    <p>_buildUI-funktionen är var vi stoppar all kod för att skapa programmets användargränssnitt. Det första steget är att skapa ett nytt <link xref="GtkApplicationWindow.js">Gtk.ApplicationWindow</link> att stoppa alla våra komponenter i.</p>
  </section>

  <section id="button">
    <title>Creating the scales</title>
    <code mime="application/javascript"><![CDATA[
        // Create the horizontal scale
        this._hScale = Gtk.Scale.new_with_range (Gtk.Orientation.HORIZONTAL, 0.0, 100.0, 5.0);
        this._hScale.set_valign (Gtk.Align.START);
        this._hScale.set_value (50);
        this._hScale.set_digits (0);
        // this._hScale.set_draw_value (false);
]]></code>

    <p>The new_with_range method is one way to create a new Scale widget. The parameters it takes are a <link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Orientation.html">Gtk.Orientation</link>, the minimum value, the maximum value, and the increment for a single step. After that we use the Scale's methods to set its starting value, and how many decimal places it runs to. We also set its vertical alignment in this case, to control where it appears in the window.</p>
    <p>We can use the set_draw_value method to tell it whether or not to show the number next to the sliding scale. It's commented out in this example.</p>

    <code mime="application/javascript"><![CDATA[
        // Create a master adjustment to use for the vertical (or any other) scale
        this._adjustment = new Gtk.Adjustment ({
            value: 95,
            lower: 0,
            upper: 100,
            step_increment: 5,
            page_increment: 10 });
]]></code>

    <p>An Adjustment is an object we can use to simplify things when creating a new Scale. The Adjustment's "value" property is what the Scale's default value is, while "upper" and "lower" make the high and low ends of the numerical range. Meanwhile, the increment values show how much the slider moves when you do things like click on it.</p>

    <code mime="application/javascript"><![CDATA[
        // Create a vertical scale using the adjustment we just made
        this._vScale = new Gtk.Scale ({
            orientation: Gtk.Orientation.VERTICAL,
            adjustment: this._adjustment,
            digits: 0,
            // draw_value: false,
            margin_left: 10 });
]]></code>

    <p>Here we create a new Scale object using _adjustment as its "adjustment" property. This is a great shortcut. We still have to tell it to round off the decimal place, though. Note that the draw_value property is commented out; this is how you tell it not to show the number next to the Scale when you're creating one this way.</p>

    <code mime="application/javascript"><![CDATA[
        // Create the label that shows the product of the two values
        this._product = (this._hScale.get_value() * this._vScale.get_value());
        this._label = new Gtk.Label ({
            label: (String(this._product) + " penguins on the iceberg."),
            height_request: 200,
            width_request: 200,
            wrap: true});

        // Connect the two scales to functions which recalculate the label
        this._hScale.connect ("value-changed", Lang.bind (this, this._recalc));
        this._vScale.connect ("value-changed", Lang.bind (this, this._recalc));
]]></code>

    <p>We can use the get_value method to find out the numerical value a Scale is set at. We can then do whatever we want with it, including multiply the two Scales' values together and have a <link xref="label.js">Label</link> show us the product. We set the label's text to wrap around, because we're having it display a silly message too.</p>
    <p>After we create the Label, we connect the two Scales' "value-changed" signals to _recalc, a function that will recalculate the number of penguins on the iceberg and come up with a new message.</p>

    <code mime="application/javascript">
        // Skapa ett rutnät att arrangera saker i
        this._UIGrid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER,
            margin_top: 20,
            margin_left: 20});

        // Fäst allting till rutnätet
        this._UIGrid.attach (this._label, 0, 0, 1, 1);
        this._UIGrid.attach (this._hScale, 0, 1, 1, 1);
        this._UIGrid.attach (this._vScale, 1, 0, 1, 1);
</code>
    <p>Här skapar vi en <link xref="grid.js">Grid</link> att stoppa allting i, och fäster sedan alla våra komponenter till den. Observera att här och på några av komponenterna själva använder vi marginaler för att få saker att hålla bra avstånd.</p>
    <code mime="application/javascript">
        // Lägg till rutnätet till fönstret
        this._window.add (this._comboBoxText);

        // Visa fönstret och alla barnkomponenter
        this._window.show_all();
    },
</code>
    <p>Slutligen lägger vi till vår Grid till fönstret, och säger sedan till fönstret att visa sig själv och alla komponenterna i det.</p>
    </section>

    <section id="scales-handler">
    <title>Function which handles the scales' values changing</title>

    <code mime="application/javascript"><![CDATA[
    _recalc: function() {

        // Figure out what the product of the two scales' values is
        var product = (this._hScale.get_value() * this._vScale.get_value());

        // Create a blank comment line in case there isn't a silly comment to make
        var comment = "";

        // Make a silly comment based on the number of penguins
        if (product > 9000) {
            comment = "It's over 9000!";
        }
        else if (product < 1000 && product > 0) {
            comment = "They're getting lonely.";
        }
        else if (product == 0) {
            comment = "They're all gone ...";
        }
        else comment = "";

        // Set ._label's new text
        this._label.set_label (String (product) + " penguins on the iceberg. " + comment);

    }

});
]]></code>
    <p>Remember, we can get a Scale's value using its get_value method. Here we simply recalculate what the product of the two values is after one of the Scales is moved, add in a silly message depending on how many penguins are left, and change the wording on _label to show the new number and message.</p>

    <code mime="application/javascript">
// Kör programmet
let app = new ScaleExample ();
app.application.run (ARGV);
</code>
    <p>Slutligen skapar vi en ny instans av den slutförda ScaleExample-klassen, och startar programmet.</p>
  </section>

  <section id="complete">
    <title>Fullständigt kodexempel</title>
<code mime="application/javascript" style="numbered">#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';

const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;

class ScaleExample {

    // Create the application itself
    constructor() {
        this.application = new Gtk.Application({
            application_id: 'org.example.jsscale'
        });

        // Connect 'activate' and 'startup' signals to the callback functions
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Callback function for 'activate' signal presents window when active
    _onActivate() {
        this._window.present();
    }

    // Callback function for 'startup' signal builds the UI
    _onStartup() {
        this._buildUI();
    }

    // Build the application's UI
    _buildUI() {

        // Create the application window
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            border_width: 20,
            title: "Birds on a Floe"});

        // Create the horizontal scale
        this._hScale = Gtk.Scale.new_with_range (Gtk.Orientation.HORIZONTAL, 0.0, 100.0, 5.0);
        this._hScale.set_valign (Gtk.Align.START);
        this._hScale.set_value (50);
        this._hScale.set_digits (0);
        // this._hScale.set_draw_value (false);

        // Create a master adjustment to use for the vertical (or any other) scale
        this._adjustment = new Gtk.Adjustment ({
            value: 95,
            lower: 0,
            upper: 100,
            step_increment: 5,
            page_increment: 10 });

        // Create a vertical scale using the adjustment we just made
        this._vScale = new Gtk.Scale ({
            orientation: Gtk.Orientation.VERTICAL,
            adjustment: this._adjustment,
            digits: 0,
            // draw_value: false,
            margin_left: 10 });

        // Create the label that shows the product of the two values
        this._product = (this._hScale.get_value() * this._vScale.get_value());
        this._label = new Gtk.Label ({
            label: (String(this._product) + " penguins on the iceberg."),
            height_request: 200,
            width_request: 200,
            wrap: true});

        // Connect the two scales to functions which recalculate the label
        this._hScale.connect ("value-changed", this._recalc.bind(this));
        this._vScale.connect ("value-changed", this._recalc.bind(this));

        // Create a grid to arrange things in
        this._UIGrid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER,
            margin_top: 20,
            margin_left: 20});

        // Attach everything to the grid
        this._UIGrid.attach (this._label, 0, 0, 1, 1);
        this._UIGrid.attach (this._hScale, 0, 1, 1, 1);
        this._UIGrid.attach (this._vScale, 1, 0, 1, 1);

        // Add the grid to the window
        this._window.add (this._UIGrid);

        // Show the window and all child widgets
        this._window.show_all();
    }

    _recalc() {

        // Figure out what the product of the two scales' values is
        var product = (this._hScale.get_value() * this._vScale.get_value());

        // Create a blank comment line in case there isn't a silly comment to make
        var comment = "";

        // Make a silly comment based on the number of penguins
        if (product &gt; 9000) {
            comment = "It's over 9000!";
        }
        else if (product &lt; 1000 &amp;&amp; product &gt; 0) {
            comment = "They're getting lonely.";
        }
        else if (product == 0) {
            comment = "They're all gone ...";
        }
        else comment = "";

        // Set ._label's new text
        this._label.set_label (String (product) + " penguins on the iceberg. " + comment);
    }
};

// Run the application
let app = new ScaleExample ();
app.application.run (ARGV);
</code>
  </section>

  <section id="in-depth">
    <title>Djupgående dokumentation</title>
<list>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Adjustment.html">Gtk.Adjustment</link></p></item>
  <item><p><link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Gtk.Application</link></p></item>
  <item><p><link href="http://developer.gnome.org/gtk3/stable/GtkApplicationWindow.html">Gtk.ApplicationWindow</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Grid.html">Gtk.Grid</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Label.html">Gtk.Label</link></p></item>
  <item><p><link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Scale.html">Gtk.Scale</link></p></item>
</list>
  </section>
</page>
