Skip to content

Commit

Permalink
deploy: 4471cbb
Browse files Browse the repository at this point in the history
  • Loading branch information
hecrj committed Mar 20, 2024
1 parent 0cf061b commit a6ec292
Show file tree
Hide file tree
Showing 8 changed files with 2,662 additions and 92 deletions.

Large diffs are not rendered by default.

Binary file not shown.
16 changes: 8 additions & 8 deletions architecture.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ <h1 class="menu-title">iced — A Cross-Platform GUI Library for Rust</h1>
<div id="content" class="content">
<main>
<h1 id="architecture"><a class="header" href="#architecture">Architecture</a></h1>
<p>Let's start from the basics! You are probably very familiar with graphical user interfaces already.
<p>Lets start from the basics! You are probably very familiar with graphical user interfaces already.
You can find them on your phone, computer, and most interactive electronic devices. In fact, you are
most likely reading this book using one!</p>
<p>At their essence, graphical user interfaces are applications that <strong>display</strong> some information graphically
Expand All @@ -189,15 +189,15 @@ <h1 id="architecture"><a class="header" href="#architecture">Architecture</a></h
<img alt="Interface displays, user interacts" src="resources/gui-displays-user-interacts.svg">
</div>
<p>The user interactions may cause the application to update and display new information as a result, which in turn
may cause further user interactions, which in turn cause further updates... And so on. This quick feedback loop
may cause further user interactions, which in turn cause further updates And so on. This quick feedback loop
is what causes the feeling of <em>interactivity</em>.</p>
<blockquote>
<p>Note: In this book, we will refer to graphical user interfaces as <strong>GUIs</strong>, <strong>UIs</strong>, <strong>user interfaces</strong>, or simply
<strong>interfaces</strong>. Technically, not all interfaces are graphical nor user-oriented; but, given the context of this
book, we will use all of these terms interchangeably.</p>
</blockquote>
<h2 id="dissecting-an-interface"><a class="header" href="#dissecting-an-interface">Dissecting an Interface</a></h2>
<p>Since we are interested in creating user interfaces, let's take a closer look at them. We will start with a very
<p>Since we are interested in creating user interfaces, lets take a closer look at them. We will start with a very
simple one: the classical counter interface. What is it made of?</p>
<div align="center">
<img alt="A classical counter interface" src="resources/counter-interface.svg">
Expand All @@ -224,7 +224,7 @@ <h2 id="the-gui-trinity"><a class="header" href="#the-gui-trinity">The GUI Trini
<p>These ideas are connected to each other, forming another feedback loop!</p>
<p><strong>Widgets</strong> produce <strong>interactions</strong> when a user interacts with them. These <strong>interactions</strong> then change the <strong>state</strong>
of the interface. The changed <strong>state</strong> propagates and dictates the new <strong>widgets</strong> that must be displayed. These new
<strong>widgets</strong> may then produce new <strong>interactions</strong>, which can change the <strong>state</strong> again... And so on.</p>
<strong>widgets</strong> may then produce new <strong>interactions</strong>, which can change the <strong>state</strong> again And so on.</p>
<div align="center">
<img alt="The GUI trinity" src="resources/the-gui-trinity.svg">
</div>
Expand All @@ -236,15 +236,15 @@ <h2 id="different-ideas-different-nature"><a class="header" href="#different-ide
<p>The state and the interactions of an interface are very specific to the application and its purpose. If I tell you that
I have an interface with a numeric value and increment and decrement interactions, you will very easily
guess I am talking about a counter interface.</p>
<p>However, if I tell you I have an interface with two buttons and a number... It's quite trickier for you to guess the kind
<p>However, if I tell you I have an interface with two buttons and a number Its quite trickier for you to guess the kind
of interface I am talking about. It could be anything!</p>
<p>This is because widgets are generally very generic and, therefore, more reusable. Most interfaces display a combination of
familiar widgets—like buttons and numbers. In fact, users expect familiar widgets to always behave a certain way. If they
don't behave properly, the interface will be unintuitive and have poor <a href="https://en.wikipedia.org/wiki/User_experience">user experience</a>.</p>
dont behave properly, the interface will be unintuitive and have poor <a href="https://en.wikipedia.org/wiki/User_experience">user experience</a>.</p>
<p>While widgets are generally very reusable; the specific widget configuration dictated by the application state and its
interactions is very application-specific. A button is generic; but a button that has a "+" label and causes a value
interactions is very application-specific. A button is generic; but a button that has a “+” label and causes a value
increment when pressed is very specific.</p>
<p>All of this means that, when we are creating a specific user interface, we don't want to focus on implementing every
<p>All of this means that, when we are creating a specific user interface, we dont want to focus on implementing every
familiar widget and its behavior. Instead, we want to leverage widgets as reusable building blocks—independent of our
application and provided by some library—while placing our focus on the application-specific parts of the fundamental
architecture: state, interactions, how the interactions change the state, and how the state dictates the widgets.</p>
Expand Down
46 changes: 23 additions & 23 deletions first-steps.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,17 @@ <h1 class="menu-title">iced — A Cross-Platform GUI Library for Rust</h1>
<div id="content" class="content">
<main>
<h1 id="first-steps"><a class="header" href="#first-steps">First Steps</a></h1>
<p>But enough with the theory. It's about time we start writing some code!</p>
<p>But enough with the theory. Its about time we start writing some code!</p>
<p>iced embraces The Elm Architecture as the most natural approach for architecting interactive applications.
Therefore, when using iced, we will be dealing with the four main ideas we introduced in the previous chapter:
<strong>state</strong>, <strong>messages</strong>, <strong>update logic</strong>, and <strong>view logic</strong>.</p>
<p>In the previous chapter, we dissected and studied the classical counter interface. Let's try to
<p>In the previous chapter, we dissected and studied the classical counter interface. Lets try to
build it in Rust while leveraging The Elm Architecture.</p>
<div align="center">
<img alt="A classical counter interface" src="resources/counter-interface-annotated.svg">
</div>
<h2 id="state"><a class="header" href="#state">State</a></h2>
<p>Let's start with the <strong>state</strong>—the underlying data of the application.</p>
<p>Lets start with the <strong>state</strong>—the underlying data of the application.</p>
<p>In Rust, given the ownership and borrowing rules, it is extremely important to think carefully about the data model
of your application.</p>
<blockquote>
Expand All @@ -199,17 +199,17 @@ <h2 id="state"><a class="header" href="#state">State</a></h2>
</blockquote>
<p>For our counter interface, all we need is a counter value. Since we have both increment and decrement interactions,
the number could potentially be negative. This means we need a signed integer.</p>
<p>Also, we know some users are crazy and they may want to count a lot of things. Let's give them 64 bits to play with:</p>
<p>Also, we know some users are crazy and they may want to count a lot of things. Lets give them 64 bits to play with:</p>
<pre><code class="language-rust">struct Counter {
value: i64,
}</code></pre>
<p>If a crazy user counted 1000 things every second, it would take them ~300 million years to run out of numbers.
Let's hope that's enough.</p>
Lets hope thats enough.</p>
<h2 id="messages"><a class="header" href="#messages">Messages</a></h2>
<p>Next, we need to define our <strong>messages</strong>—the interactions of the application.</p>
<p>Our counter interface has two interactions: <strong>increment</strong> and <strong>decrement</strong>. Technically, we could use a simple boolean to
encode these interactions: <code>true</code> for increment and <code>false</code> for decrement, for instance.</p>
<p>But... we can do better in Rust! Interactions are mutually exclusive—when we have an interaction, what we really have is one
<p>But we can do better in Rust! Interactions are mutually exclusive—when we have an interaction, what we really have is one
value of a possible set of values. It turns out that Rust has the perfect data type for modeling this kind of idea: the <em>enum</em>.</p>
<p>Thus, we can define our messages like this:</p>
<pre><code class="language-rust">enum Message {
Expand All @@ -219,7 +219,7 @@ <h2 id="messages"><a class="header" href="#messages">Messages</a></h2>
<p>Simple enough! This also sets us up for the long-term. If we ever wanted to add additional interactions to our application—like a
<code>Reset</code> interaction, for instance—we could just introduce additional variants to this type. Enums are very powerful and convenient.</p>
<h2 id="update-logic"><a class="header" href="#update-logic">Update Logic</a></h2>
<p>Now, it's time for our <strong>update logic</strong>—how messages change the state of the application.</p>
<p>Now, its time for our <strong>update logic</strong>—how messages change the state of the application.</p>
<p>Basically, we need to write some logic that given any message can update any state of the application accordingly. The simplest
and most idiomatic way to express this logic in Rust is by defining a method named <code>update</code> in our application state.</p>
<p>For our counter interface, we only need to properly increment or decrement the <code>value</code> of our <code>Counter</code> struct based on the <code>Message</code>
Expand All @@ -238,7 +238,7 @@ <h2 id="update-logic"><a class="header" href="#update-logic">Update Logic</a></h
}</code></pre>
<p>Great! Now we are ready to process user interactions. For instance, imagine we initialized our counter like this:</p>
<pre><code class="language-rust ignore">let mut counter = Counter { value: 0 };</code></pre>
<p>And let's say we wanted to simulate a user playing with our interface for a bit—pressing the increment button twice
<p>And lets say we wanted to simulate a user playing with our interface for a bit—pressing the increment button twice
and then the decrement button once. We could easily compute the final state of our counter with our <strong>update logic</strong>:</p>
<pre><code class="language-rust ignore">counter.update(Message::Increment);
counter.update(Message::Increment);
Expand All @@ -257,7 +257,7 @@ <h2 id="update-logic"><a class="header" href="#update-logic">Update Logic</a></h
assert_eq!(counter.value, 1);
}</code></pre>
<p>Notice how easy this was to write! So far, we are just leveraging very simple Rust concepts. No dependencies in sight!
You may even be wondering... "Where is the GUI code?!"</p>
You may even be wondering… “Where is the GUI code?!</p>
<p>This is one of the main advantages of The Elm Architecture. As we discovered in the previous chapter, widgets are the
only fundamental idea of an interface that is reusable in nature. All the parts we have defined so far are application-specific
and, therefore, do not need to know about the UI library at all!</p>
Expand All @@ -276,15 +276,15 @@ <h2 id="view-logic"><a class="header" href="#view-logic">View Logic</a></h2>
<p>And this is where <strong>iced</strong> comes in—finally! iced is a cross-platform GUI library for Rust. It packages a fair collection of
ready-to-use widgets; buttons and numbers included. Exactly what we need for our counter.</p>
<h3 id="the-buttons"><a class="header" href="#the-buttons">The Buttons</a></h3>
<p>Our counter interface has two <strong>buttons</strong>. Let's see how we can define them using iced.</p>
<p>Our counter interface has two <strong>buttons</strong>. Lets see how we can define them using iced.</p>
<p>In iced, widgets are independent values. The same way you can have an integer in a variable, you can have a widget as well.
These values are normally created using a <em>helper function</em> from the <code>widget</code> module.</p>
<p>For our buttons, we can use the <code>button</code> helper:</p>
<pre><code class="language-rust ignore">use iced::widget::button;

let increment = button("+");
let decrement = button("-");</code></pre>
<p>That's quite simple, isn't it? For now, we have just defined a couple of variables for our buttons.</p>
<p>Thats quite simple, isnt it? For now, we have just defined a couple of variables for our buttons.</p>
<p>As we can see, widget helpers may take arguments for configuring parts of the widgets to our liking.
In this case, the <code>button</code> function takes a single argument used to describe the contents of the button.</p>
<h3 id="the-number"><a class="header" href="#the-number">The Number</a></h3>
Expand All @@ -295,18 +295,18 @@ <h3 id="the-number"><a class="header" href="#the-number">The Number</a></h3>
<pre><code class="language-rust ignore">use iced::widget::text;

let counter = text(15);</code></pre>
<p>Sweet! Like <code>button</code>, <code>text</code> also takes an argument used to describe its contents. Since we are just getting started, let's
<p>Sweet! Like <code>button</code>, <code>text</code> also takes an argument used to describe its contents. Since we are just getting started, lets
simply hardcode <code>15</code> for now.</p>
<h3 id="the-layout"><a class="header" href="#the-layout">The Layout</a></h3>
<p>Alright! We have our two buttons in <code>increment</code> and <code>decrement</code>, and our counter value in <code>counter</code>. That should be everything, right?</p>
<p>Not so fast! The widgets in our counter interface are displayed in a specific <strong>order</strong>. Given our three widgets, there is a total of
<strong>six</strong> different ways to order them. However, the order we want is: <code>increment</code>, <code>counter</code>, and <code>decrement</code>.</p>
<p>A very simple way of describing this order is to create a list with our widgets:</p>
<pre><code class="language-rust ignore">let interface = vec![increment, counter, decrement];</code></pre>
<p>But we are still missing something! It's not only the order that is specific, our interface also has a specific visual <strong>layout</strong>.</p>
<p>But we are still missing something! Its not only the order that is specific, our interface also has a specific visual <strong>layout</strong>.</p>
<p>The widgets are positioned on top of each other, but they could very well be positioned from left to right instead. There is nothing
in our description so far that talks about the <strong>layout</strong> of our widgets.</p>
<p>In iced, layout is described using... well, more widgets! That's right. Not all widgets produce visual results directly; some may simply
<p>In iced, layout is described using well, more widgets! Thats right. Not all widgets produce visual results directly; some may simply
manage the position of existing widgets. And since widgets are just values, they can be nested and composed nicely.</p>
<p>The kind of vertical layout that we need for our counter can be achieved with the <code>column</code> widget:</p>
<pre><code class="language-rust ignore">use iced::widget::column;
Expand All @@ -318,8 +318,8 @@ <h3 id="the-interactions"><a class="header" href="#the-interactions">The Interac
<p>At this point, we have in our <code>interface</code> variable a <code>column</code> representing our counter interface. But if we actually tried to run it,
we would quickly find out that something is wrong.</p>
<p>Our buttons would be completely disabled. Of course! We have not defined any <strong>interactions</strong> for them. Notice that we have yet
to use our <code>Message</code> enum in our view logic. How is our user interface supposed to produce <strong>messages</strong> if we don't specify
them? Let's do that now.</p>
to use our <code>Message</code> enum in our view logic. How is our user interface supposed to produce <strong>messages</strong> if we dont specify
them? Lets do that now.</p>
<p>In iced, every widget has a specific type that enables further configuration using simple builder methods. The <code>button</code>
helper returns an instance of <a href="https://docs.rs/iced/0.12.1/iced/widget/struct.Button.html">the <code>Button</code> type</a>, which has an <code>on_press</code> method we can use to define the message it must
<strong>produce</strong> when a user presses the button:</p>
Expand All @@ -339,7 +339,7 @@ <h3 id="the-interactions"><a class="header" href="#the-interactions">The Interac
to derive <code>Debug</code> and <code>Clone</code> for our <code>Message</code> type.</p>
<h3 id="the-view"><a class="header" href="#the-view">The View</a></h3>
<p>We are almost there! There is only one thing left to do: connecting our application <strong>state</strong> to the view logic.</p>
<p>Let's bring together all the view logic we have written so far:</p>
<p>Lets bring together all the view logic we have written so far:</p>
<pre><code class="language-rust ignore">use iced::widget::{button, column, text};

// The buttons
Expand Down Expand Up @@ -374,9 +374,9 @@ <h3 id="the-view"><a class="header" href="#the-view">The View</a></h3>
}</code></pre>
<p>Our <code>counter</code> variable now will always have a <code>text</code> widget with the current <code>value</code> of our <code>Counter</code>. Great!</p>
<p>However, and as you may have noticed, this <code>view</code> method is completely useless—it constructs an
<code>interface</code>, but then... It does nothing with it and throws it away!</p>
<code>interface</code>, but then It does nothing with it and throws it away!</p>
<blockquote>
<p>In iced, constructing and configuring widgets has no side effects. There is no "global context" you need to
<p>In iced, constructing and configuring widgets has no side effects. There is no global context you need to
worry about in your view code.</p>
</blockquote>
<p>Instead of throwing the <code>interface</code> away, we need to return it. Remember, the purpose of our <strong>view logic</strong> is
Expand Down Expand Up @@ -408,8 +408,8 @@ <h3 id="the-view"><a class="header" href="#the-view">The View</a></h3>
<p>iced has a strong focus on type safety—leveraging the type system and compile-time guarantees to minimize runtime errors
as much as possible.</p>
</blockquote>
<p>And well... That's it! Our view logic is done! But wait... It's a bit verbose right now. Since it's such a simple interface,
let's just inline everything:</p>
<p>And well Thats it! Our view logic is done! But wait Its a bit verbose right now. Since its such a simple interface,
lets just inline everything:</p>
<div align="center" class="right">
<img alt="A classical counter interface" src="resources/counter-interface.svg" width="50%">
</div>
Expand All @@ -424,10 +424,10 @@ <h3 id="the-view"><a class="header" href="#the-view">The View</a></h3>
]
}
}</code></pre>
<p>That's much more concise. It even resembles the actual interface! Since creating widgets just yields values with no
<p>Thats much more concise. It even resembles the actual interface! Since creating widgets just yields values with no
side effects; we can move things around in our view logic without worrying about breaking other stuff. No spooky
action at a distance!</p>
<p>And that's all there is to our counter interface. I am sure you can't wait to <strong>run</strong> it. Shall we?</p>
<p>And thats all there is to our counter interface. I am sure you cant wait to <strong>run</strong> it. Shall we?</p>

</main>

Expand Down
Loading

0 comments on commit a6ec292

Please sign in to comment.