Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/FlyString.h>
28#include <AK/JsonValue.h>
29#include <LibGUI/Variant.h>
30
31namespace GUI {
32
33const char* to_string(Variant::Type type)
34{
35 switch (type) {
36 case Variant::Type::Invalid:
37 return "Invalid";
38 case Variant::Type::Bool:
39 return "Bool";
40 case Variant::Type::Int32:
41 return "Int32";
42 case Variant::Type::Int64:
43 return "Int64";
44 case Variant::Type::UnsignedInt:
45 return "UnsignedInt";
46 case Variant::Type::Float:
47 return "Float";
48 case Variant::Type::String:
49 return "String";
50 case Variant::Type::Bitmap:
51 return "Bitmap";
52 case Variant::Type::Color:
53 return "Color";
54 case Variant::Type::Icon:
55 return "Icon";
56 case Variant::Type::Point:
57 return "Point";
58 case Variant::Type::Size:
59 return "Size";
60 case Variant::Type::Rect:
61 return "Rect";
62 case Variant::Type::Font:
63 return "Font";
64 }
65 ASSERT_NOT_REACHED();
66}
67
68Variant::Variant()
69{
70 m_value.as_string = nullptr;
71}
72
73Variant::~Variant()
74{
75 clear();
76}
77
78void Variant::clear()
79{
80 switch (m_type) {
81 case Type::String:
82 AK::unref_if_not_null(m_value.as_string);
83 break;
84 case Type::Bitmap:
85 AK::unref_if_not_null(m_value.as_bitmap);
86 break;
87 case Type::Icon:
88 AK::unref_if_not_null(m_value.as_icon);
89 break;
90 default:
91 break;
92 }
93 m_type = Type::Invalid;
94 m_value.as_string = nullptr;
95}
96
97Variant::Variant(i32 value)
98 : m_type(Type::Int32)
99{
100 m_value.as_i32 = value;
101}
102
103Variant::Variant(i64 value)
104 : m_type(Type::Int64)
105{
106 m_value.as_i64 = value;
107}
108
109Variant::Variant(unsigned value)
110 : m_type(Type::UnsignedInt)
111{
112 m_value.as_uint = value;
113}
114
115Variant::Variant(float value)
116 : m_type(Type::Float)
117{
118 m_value.as_float = value;
119}
120
121Variant::Variant(bool value)
122 : m_type(Type::Bool)
123{
124 m_value.as_bool = value;
125}
126
127Variant::Variant(const char* cstring)
128 : Variant(String(cstring))
129{
130}
131
132Variant::Variant(const FlyString& value)
133 : Variant(String(value.impl()))
134{
135}
136
137Variant::Variant(const String& value)
138 : m_type(Type::String)
139{
140 m_value.as_string = const_cast<StringImpl*>(value.impl());
141 AK::ref_if_not_null(m_value.as_string);
142}
143
144Variant::Variant(const JsonValue& value)
145{
146 if (value.is_null()) {
147 m_value.as_string = nullptr;
148 return;
149 }
150
151 if (value.is_i32()) {
152 m_type = Type::Int32;
153 m_value.as_i32 = value.as_i32();
154 return;
155 }
156
157 if (value.is_u32()) {
158 m_type = Type::UnsignedInt;
159 m_value.as_uint = value.as_u32();
160 return;
161 }
162
163 if (value.is_i64()) {
164 m_type = Type::Int64;
165 m_value.as_i64 = value.as_i64();
166 return;
167 }
168
169 if (value.is_u64()) {
170 // FIXME: Variant should have a 64-bit internal type.
171 m_type = Type::UnsignedInt;
172 m_value.as_uint = value.to_u32();
173 return;
174 }
175
176 if (value.is_string()) {
177 m_type = Type::String;
178 m_value.as_string = value.as_string().impl();
179 m_value.as_string->ref();
180 return;
181 }
182
183 if (value.is_bool()) {
184 m_type = Type::Bool;
185 m_value.as_bool = value.as_bool();
186 return;
187 }
188
189 ASSERT_NOT_REACHED();
190}
191
192Variant::Variant(const Gfx::Bitmap& value)
193 : m_type(Type::Bitmap)
194{
195 m_value.as_bitmap = const_cast<Gfx::Bitmap*>(&value);
196 AK::ref_if_not_null(m_value.as_bitmap);
197}
198
199Variant::Variant(const GUI::Icon& value)
200 : m_type(Type::Icon)
201{
202 m_value.as_icon = &const_cast<GUI::IconImpl&>(value.impl());
203 AK::ref_if_not_null(m_value.as_icon);
204}
205
206Variant::Variant(const Gfx::Font& value)
207 : m_type(Type::Font)
208{
209 m_value.as_font = &const_cast<Gfx::Font&>(value);
210 AK::ref_if_not_null(m_value.as_font);
211}
212
213Variant::Variant(Color color)
214 : m_type(Type::Color)
215{
216 m_value.as_color = color.value();
217}
218
219Variant::Variant(const Gfx::Point& point)
220 : m_type(Type::Point)
221{
222 m_value.as_point = { point.x(), point.y() };
223}
224
225Variant::Variant(const Gfx::Size& size)
226 : m_type(Type::Size)
227{
228 m_value.as_size = { size.width(), size.height() };
229}
230
231Variant::Variant(const Gfx::Rect& rect)
232 : m_type(Type::Rect)
233{
234 m_value.as_rect = (const RawRect&)rect;
235}
236
237Variant& Variant::operator=(const Variant& other)
238{
239 if (&other == this)
240 return *this;
241 clear();
242 copy_from(other);
243 return *this;
244}
245
246Variant& Variant::operator=(Variant&& other)
247{
248 if (&other == this)
249 return *this;
250 // FIXME: Move, not copy!
251 clear();
252 copy_from(other);
253 other.clear();
254 return *this;
255}
256
257Variant::Variant(const Variant& other)
258{
259 copy_from(other);
260}
261
262void Variant::copy_from(const Variant& other)
263{
264 ASSERT(!is_valid());
265 m_type = other.m_type;
266 switch (m_type) {
267 case Type::Bool:
268 m_value.as_bool = other.m_value.as_bool;
269 break;
270 case Type::Int32:
271 m_value.as_i32 = other.m_value.as_i32;
272 break;
273 case Type::Int64:
274 m_value.as_i64 = other.m_value.as_i64;
275 break;
276 case Type::UnsignedInt:
277 m_value.as_uint = other.m_value.as_uint;
278 break;
279 case Type::Float:
280 m_value.as_float = other.m_value.as_float;
281 break;
282 case Type::String:
283 m_value.as_string = other.m_value.as_string;
284 AK::ref_if_not_null(m_value.as_bitmap);
285 break;
286 case Type::Bitmap:
287 m_value.as_bitmap = other.m_value.as_bitmap;
288 AK::ref_if_not_null(m_value.as_bitmap);
289 break;
290 case Type::Icon:
291 m_value.as_icon = other.m_value.as_icon;
292 AK::ref_if_not_null(m_value.as_icon);
293 break;
294 case Type::Font:
295 m_value.as_font = other.m_value.as_font;
296 AK::ref_if_not_null(m_value.as_font);
297 break;
298 case Type::Color:
299 m_value.as_color = other.m_value.as_color;
300 break;
301 case Type::Point:
302 m_value.as_point = other.m_value.as_point;
303 break;
304 case Type::Size:
305 m_value.as_size = other.m_value.as_size;
306 break;
307 case Type::Rect:
308 m_value.as_rect = other.m_value.as_rect;
309 break;
310 case Type::Invalid:
311 break;
312 }
313}
314
315bool Variant::operator==(const Variant& other) const
316{
317 if (m_type != other.m_type)
318 return to_string() == other.to_string();
319 switch (m_type) {
320 case Type::Bool:
321 return as_bool() == other.as_bool();
322 case Type::Int32:
323 return as_i32() == other.as_i32();
324 case Type::Int64:
325 return as_i64() == other.as_i64();
326 case Type::UnsignedInt:
327 return as_uint() == other.as_uint();
328 case Type::Float:
329 return as_float() == other.as_float();
330 case Type::String:
331 return as_string() == other.as_string();
332 case Type::Bitmap:
333 return m_value.as_bitmap == other.m_value.as_bitmap;
334 case Type::Icon:
335 return m_value.as_icon == other.m_value.as_icon;
336 case Type::Color:
337 return m_value.as_color == other.m_value.as_color;
338 case Type::Point:
339 return as_point() == other.as_point();
340 case Type::Size:
341 return as_size() == other.as_size();
342 case Type::Rect:
343 return as_rect() == other.as_rect();
344 case Type::Font:
345 return &as_font() == &other.as_font();
346 case Type::Invalid:
347 return true;
348 }
349 ASSERT_NOT_REACHED();
350}
351
352bool Variant::operator<(const Variant& other) const
353{
354 if (m_type != other.m_type)
355 return to_string() < other.to_string();
356 switch (m_type) {
357 case Type::Bool:
358 return as_bool() < other.as_bool();
359 case Type::Int32:
360 return as_i32() < other.as_i32();
361 case Type::Int64:
362 return as_i64() < other.as_i64();
363 case Type::UnsignedInt:
364 return as_uint() < other.as_uint();
365 case Type::Float:
366 return as_float() < other.as_float();
367 case Type::String:
368 return as_string() < other.as_string();
369 case Type::Bitmap:
370 // FIXME: Maybe compare bitmaps somehow differently?
371 return m_value.as_bitmap < other.m_value.as_bitmap;
372 case Type::Icon:
373 // FIXME: Maybe compare icons somehow differently?
374 return m_value.as_icon < other.m_value.as_icon;
375 case Type::Color:
376 return m_value.as_color < other.m_value.as_color;
377 case Type::Point:
378 case Type::Size:
379 case Type::Rect:
380 case Type::Font:
381 // FIXME: Figure out how to compare these.
382 ASSERT_NOT_REACHED();
383 case Type::Invalid:
384 break;
385 }
386 ASSERT_NOT_REACHED();
387}
388
389String Variant::to_string() const
390{
391 switch (m_type) {
392 case Type::Bool:
393 return as_bool() ? "true" : "false";
394 case Type::Int32:
395 return String::number(as_i32());
396 case Type::Int64:
397 return String::number(as_i64());
398 case Type::UnsignedInt:
399 return String::number(as_uint());
400 case Type::Float:
401 return String::format("%.2f", (double)as_float());
402 case Type::String:
403 return as_string();
404 case Type::Bitmap:
405 return "[Gfx::Bitmap]";
406 case Type::Icon:
407 return "[GUI::Icon]";
408 case Type::Color:
409 return as_color().to_string();
410 case Type::Point:
411 return as_point().to_string();
412 case Type::Size:
413 return as_size().to_string();
414 case Type::Rect:
415 return as_rect().to_string();
416 case Type::Font:
417 return String::format("[Font: %s]", as_font().name().characters());
418 case Type::Invalid:
419 return "[null]";
420 break;
421 }
422 ASSERT_NOT_REACHED();
423}
424
425}