Skip to content

Commit 57bed31

Browse files
committed
Docs: about page, syntax highlighting, cmake install link
1 parent c981efd commit 57bed31

File tree

5 files changed

+339
-23
lines changed

5 files changed

+339
-23
lines changed

docs/_data/navigation.yml

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
- label: "Home"
22
url: "/"
33

4+
- label: "About"
5+
url: "about"
6+
47
- label: "Gallery"
58
url: "gallery"
69

docs/_sass/_syntax-highlighting.scss

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
.highlight
2+
{
3+
table td { padding: 5px; }
4+
table pre { margin: 0; }
5+
6+
.bp { color: #999 } // Name.Builtin.Pseudo
7+
.c { color: #009926; font-style: italic } // Comment
8+
.c1 { color: #009926; font-style: italic } // Comment.Single
9+
.cm { color: #009926; font-style: italic } // Comment.Multiline
10+
.cp { color: #c33f40; } // Comment.Preproc
11+
.cs { color: #999; font-style: italic } // Comment.Special
12+
.err { color: #a61717 } // Error
13+
.gd { color: #000; background-color: #fdd } // Generic.Deleted
14+
.gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific
15+
.ge { font-style: italic } // Generic.Emph
16+
.gh { color: #999 } // Generic.Heading
17+
.gi { color: #000; background-color: #dfd } // Generic.Inserted
18+
.gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific
19+
.go { color: #888 } // Generic.Output
20+
.gp { color: #555 } // Generic.Prompt
21+
.gr { color: #a00 } // Generic.Error
22+
// .gs { } // Generic.Strong
23+
.gt { color: #a00 } // Generic.Traceback
24+
.gu { color: #aaa } // Generic.Subheading
25+
.il { color: #099 } // Literal.Number.Integer.Long
26+
.k { color: #0000ff } // Keyword
27+
// .kc { } // Keyword.Constant
28+
// .kd { } // Keyword.Declaration
29+
// .kp { } // Keyword.Pseudo
30+
.kr { color: #0000ff; } // Keyword.Reserved
31+
.kt { color: #0000ff; } // Keyword.Type
32+
.m { color: #099 } // Literal.Number
33+
.mf { color: #099 } // Literal.Number.Float
34+
.mh { color: #099 } // Literal.Number.Hex
35+
.mi { color: #099 } // Literal.Number.Integer
36+
.mo { color: #099 } // Literal.Number.Oct
37+
.n { color: #000 } // Name
38+
.na { color: #008080 } // Name.Attribute
39+
.nb { color: #0086B3 } // Name.Builtin
40+
.nc { color: #000; } // Name.Class
41+
.ne { color: #900; } // Name.Exception
42+
.nf { color: #900; } // Name.Function
43+
.ni { color: #800080 } // Name.Entity
44+
.nl { color: #0000ff }
45+
.nn { color: #555 } // Name.Namespace
46+
.no { color: #008080 } // Name.Constant
47+
.nt { color: #000080 } // Name.Tag
48+
.nv { color: #008080 } // Name.Variable
49+
.o { color: #008080 } // Operator
50+
.ow { color: #000080 } // Operator.Word
51+
.p { color: #008000 } // Punctuation
52+
.s { color: #d14 } // Literal.String
53+
.s1 { color: #d14 } // Literal.String.Single
54+
.s2 { color: #d14 } // Literal.String.Double
55+
.sb { color: #d14 } // Literal.String.Backtick
56+
.sc { color: #d14 } // Literal.String.Char
57+
.sd { color: #d14 } // Literal.String.Doc
58+
.se { color: #d14 } // Literal.String.Escape
59+
.sh { color: #d14 } // Literal.String.Heredoc
60+
.si { color: #d14 } // Literal.String.Interpol
61+
.sr { color: #009926 } // Literal.String.Regex
62+
.ss { color: #990073 } // Literal.String.Symbol
63+
.sx { color: #d14 } // Literal.String.Other
64+
.vc { color: #008080 } // Name.Variable.Class
65+
.vg { color: #008080 } // Name.Variable.Global
66+
.vi { color: #008080 } // Name.Variable.Instance
67+
.w { color: #bbb } // Text.Whitespace
68+
}

docs/about.md

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
---
2+
---
3+
# About
4+
5+
## History
6+
7+
<div class = "img-align-right" style="width:35%">
8+
<img src="assets/images/hdpi.png" alt="HDPI Image">
9+
<p>HDPI Matters. Zoom in and notice the standard DPI icons at the top
10+
(e.g. the Power Button from the VST3 Plug-in Test Host), vs. Elements’
11+
vector dials.</p>
12+
</div>
13+
14+
Sometime in 2014, I started searching for a GUI library I can use for some of
15+
the projects I am developing. The most important requirements to me were:
16+
17+
1. It should be open source with a liberal, non-viral license.
18+
2. It should be usable in any application and should play well with other GUI
19+
libraries and frameworks.
20+
3. Corollary to the second requirement is that it can also be used
21+
to develop plugins (e.g. it should not own the event loop and can co-exist
22+
with elements within a plugin host such as VST and AU.
23+
4. It should be resolution independent and allows for HDPI displays.
24+
25+
I tried hard to find something that satisfies these requirements. I failed.
26+
I did not find any. JUCE comes close, but it did not satisfy the first requirement.
27+
iPlug is usable. I actually prototyped some plugins using it,
28+
but it did not satisfy the 4th requirement.
29+
I’m also unsure if it satisfies the 2nd requirement.
30+
31+
There are other requirements, such as not relying on a “visual” GUI editor or
32+
code generator. IMO, the GUI should be declared in the code. Obviously,
33+
good design and architecture is also another requirement. Most GUI C++ libraries
34+
are just too 90s for me to consider. None of that crappy OOP bleh! But, hey,
35+
I am digressing! The truth is, I am even willing to use a library with
36+
a pure C interface, such as GLFW, as long as it is well designed
37+
(GLFW is simple and clean) and can be wrapped in C++ anyway. I also tried to use
38+
NanoVG — not really a GUI library, but it makes it easier to write one (NanoVG
39+
inspired Elements’ Cairo based vector graphics canvas).
40+
41+
I know that perfect is the enemy of the good, but I just can’t resist it.
42+
I couldn’t stand it anymore. So at around 2016, I decided to write my own.
43+
Actually, I did not start from scratch. I had a head start:
44+
I’ve been writing GUI libraries since the 90s. One of the main projects I got
45+
involved with when I was working in Japan in the 90s was a lightweight
46+
GUI library named Pica. So I went ahead, dusted off the old code and rewrote it
47+
from the ground up using modern C++.
48+
49+
## Flyweight
50+
51+
Elements, is very lightweight… and extremely modular. You compose very fine-grained,
52+
flyweight “elements” to form deep element hierarchies using a declarative
53+
interface with heavy emphasis on reuse. A specific example should make it clear.
54+
Here’s the standard message box (included in elements’ gallery a collection of
55+
reusable element compositions):
56+
57+
```cpp
58+
inline auto message_box1(
59+
char const* message
60+
, std::uint32_t icon_id
61+
, char const* ok_text = "OK"
62+
, size size_ = get_theme().message_box_size
63+
, color ok_color = get_theme().indicator_color
64+
)
65+
{
66+
auto textbox = static_text_box{ message };
67+
auto ok_button = share(button(ok_text, 1.0, ok_color));
68+
auto popup = share(
69+
key_intercept(align_center_middle(
70+
fixed_size(size_,
71+
layer(
72+
margin({ 20, 20, 20, 20 },
73+
vtile(
74+
htile(
75+
align_top(icon{ icon_id, 2.5 }),
76+
left_margin(20, std::move(textbox))
77+
),
78+
align_right(hsize(100, hold(ok_button)))
79+
)
80+
),
81+
panel{}
82+
)))));
83+
popup->on_key =
84+
[ok_ = get(ok_button)](auto k)
85+
{
86+
if (k.key == key_code::enter)
87+
{
88+
if (auto ok = ok_.lock())
89+
ok->value(true);
90+
return true;
91+
}
92+
return false;
93+
};
94+
return std::pair{ ok_button, popup };
95+
}
96+
```
97+
98+
The client uses the gallery code above like this:
99+
100+
```cpp
101+
void quantum_bs(view& view_)
102+
{
103+
char const* alert_text =
104+
"We are being called to explore the cosmos itself as an "
105+
"interface between will and energy. It is a sign of things "
106+
"to come. The dreamtime is approaching a tipping point."
107+
;
108+
auto [ok_button, popup] = message_box1(alert_text, icons::attention);
109+
view_.add(popup);
110+
ok_button->on_click =
111+
[](bool state)
112+
{
113+
// Do something here when the button is clicked
114+
};
115+
}
116+
```
117+
118+
![Message box image](assets/images/message_box.jpg)
119+
120+
Some quick highlights, beyond the obvious:
121+
122+
- `share`: This element is supposed to be shared (using std::shared_ptr).
123+
E.g. when returned from functions like this one. Typically you’d want to share
124+
elements that you need to have access to elsewhere in your code.
125+
- `hold`: Hold a shared element somewhere in a view hierarchy.
126+
- `key_intercept`: A delegate element that intercepts key-presses.
127+
- `fixed_size`: An element that fixes the size of its contained element
128+
(Elements are extremely lightweight, and typically, do not even have sizes
129+
nor know their positions in the view hierarchy).
130+
- `margin`, `left_margin`: Two of the many margins, including `right_margin`,
131+
`top_margin`, etc., adds some padding, `margin` in this case 20 pixels all
132+
around the contained element, while `left_margin` adds a padding of 20 to
133+
separate the icon and the text box.
134+
- `layer`: Element composites that place elements in multiple layers.
135+
- `panel`: A simple window-like panel box.
136+
- `vtile`, `htile`: Fluid vertical and horizontal layout elements that allocate
137+
enough space for their contained elements allowing for ‘stretchiness’
138+
(the ability of elements to stretch within a defined minimum and maximum size
139+
limits; elements can have infinite sizes) as well as fixed sizing and vertical
140+
and horizontal alignment (0% to 100%). Vertical and horizontal tiles are used
141+
all over the place to place elements in a grid.
142+
- `align_top`, `align_right`, `align_center_middle`: Aligns its element to the
143+
top, right, and center (horizontally) middle (vertically), respectively.
144+
Like the margins, we have a lot of these align elements.
145+
- `on_key`: Attaches a call-back (lambda) function to the key_intercept element
146+
(strategically placed in the outermost level), to send a value of true to the
147+
ok_button, essentially programmatically clicking it when the user presses
148+
the enter key.
149+
- `get`: To avoid `shared_ptr` cycles, we use a `weak_pointer`, via the get
150+
function. We’ll need to “lock” this to get the actual shared pointer later
151+
in the callback.
152+
153+
Modularity and reuse are two of the most important design aspects. For example,
154+
the button element is actually composed of even smaller elements. Here’s part of
155+
the code responsible for making the buttons above (also in the gallery):
156+
157+
```cpp
158+
auto constexpr button_margin = rect{ 10, 5, 10, 5 };
159+
template <typename Button>
160+
inline Button make_button(
161+
std::string const& text
162+
, float size = 1.0
163+
, color body_color = get_theme().default_button_color
164+
)
165+
{
166+
return make_button<Button>(
167+
margin(
168+
button_margin,
169+
align_center(label(text, size))
170+
),
171+
body_color
172+
);
173+
}
174+
```
175+
176+
After a while, code reuse, using a palette of fine-grained elements, becomes
177+
very familiar and intuitive, much like using HTML. The declarative C++ code
178+
tells you what rather than how (imperative).
179+
180+
And, as promised, the elements are very fine grained. Here’s the actual button
181+
class we are using here:
182+
183+
```cpp
184+
class layered_button : public array_composite<2, deck_element>
185+
{
186+
public:
187+
using base_type = array_composite<2, deck_element>;
188+
using button_function = std::function<void(bool)>;
189+
using base_type::value;
190+
template <typename W1, typename W2>
191+
layered_button(W1&& off, W2&& on);
192+
virtual element* hit_test(context const& ctx, point p) override;
193+
virtual element* click(context const& ctx, mouse_button btn) override;
194+
virtual void drag(context const& ctx, mouse_button btn) override;
195+
virtual bool is_control() const override;
196+
virtual void value(int new_state) override;
197+
virtual void value(bool new_state) override;
198+
bool value() const;
199+
button_function on_click;
200+
protected:
201+
bool state(bool new_state);
202+
private:
203+
bool _state;
204+
};
205+
```
206+
207+
The layered button is a type of button that basically has two states:
208+
pushed and un-pushed. It does not know how to draw the two states. Rather,
209+
it delegates the states to two elements, composed as a 2-layer composite element,
210+
using the deck element. The class itself has nothing more than a single(!)
211+
member variable _state. That’s it! And talking about flexibility,
212+
the deck is generic and may contain any kind of element, or even your own custom
213+
drawable element. Here’s an example of a custom element that draws an infinitely
214+
resizable filled round-rectangle:
215+
216+
```cpp
217+
auto box = min_size({ 5, 5 },
218+
basic(
219+
[](context const& ctx)
220+
{
221+
auto& c = ctx.canvas;
222+
c.begin_path();
223+
c.round_rect(ctx.bounds, 4);
224+
c.fill_style(colors::gold.opacity(0.8));
225+
c.fill();
226+
}
227+
)
228+
);
229+
```
230+
231+
Elements has its own HTML5 inspired canvas drawing engine using Cairo underneath.
232+
233+
## For now...
234+
235+
There’s obviously still a lot to cover, but for now, this quick tour of Elements
236+
should suffice. Is it ready yet? Is it usable? Well, I am already using it,
237+
at least for the MacOS, which is my preferred development system. I am using it
238+
in the Ascend project. But, I have to be honest. While it is usable, and based
239+
on very solid architecture and design, there is still a lot of work to do.
240+
241+
And so that being said, if anyone out there, familiar with modern C++
242+
(esp. C++14 and C++17), finds this brief introduction compelling enough,
243+
I would very much welcome some help. Hey, this is Open Source. The license will
244+
remain permissive and liberal (currently MIT).
245+
Send me an email! joel-at-cycfi-dot-com.

docs/assets/css/style.scss

+6-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
---
33

44
@import "{{ site.theme }}";
5+
@import "syntax-highlighting";
56

67
.main-content h1,
78
.main-content h2,
@@ -42,14 +43,12 @@ img
4243
background-color: #ffffff;
4344
}
4445

45-
.highlight .cp,
46-
.highlight .mi,
47-
.highlight .n, .highlight .nf,
48-
.highlight .o,
49-
.highlight .p,
50-
.highlight .k, .highlight .kt, .highlight .kv
46+
.highlight
5147
{
52-
font-weight: normal;
48+
.cp, .mi, .n, .nc, .nf, .nl, .o, .p, .k, .kr, .kt, .kv
49+
{
50+
font-weight: normal;
51+
}
5352
}
5453

5554
.img-align-right

0 commit comments

Comments
 (0)