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/JsonValue.h>
28#include <LibGUI/Variant.h>
29
30namespace GUI {
31
32const char* to_string(Variant::Type type)
33{
34 switch (type) {
35 case Variant::Type::Invalid:
36 return "Invalid";
37 case Variant::Type::Bool:
38 return "Bool";
39 case Variant::Type::Int32:
40 return "Int32";
41 case Variant::Type::Int64:
42 return "Int64";
43 case Variant::Type::UnsignedInt:
44 return "UnsignedInt";
45 case Variant::Type::Float:
46 return "Float";
47 case Variant::Type::String:
48 return "String";
49 case Variant::Type::Bitmap:
50 return "Bitmap";
51 case Variant::Type::Color:
52 return "Color";
53 case Variant::Type::Icon:
54 return "Icon";
55 case Variant::Type::Point:
56 return "Point";
57 case Variant::Type::Size:
58 return "Size";
59 case Variant::Type::Rect:
60 return "Rect";
61 case Variant::Type::Font:
62 return "Font";
63 }
64 ASSERT_NOT_REACHED();
65}
66
67Variant::Variant()
68{
69 m_value.as_string = nullptr;
70}
71
72Variant::~Variant()
73{
74 clear();
75}
76
77void Variant::clear()
78{
79 switch (m_type) {
80 case Type::String:
81 AK::unref_if_not_null(m_value.as_string);
82 break;
83 case Type::Bitmap:
84 AK::unref_if_not_null(m_value.as_bitmap);
85 break;
86 case Type::Icon:
87 AK::unref_if_not_null(m_value.as_icon);
88 break;
89 default:
90 break;
91 }
92 m_type = Type::Invalid;
93 m_value.as_string = nullptr;
94}
95
96Variant::Variant(i32 value)
97 : m_type(Type::Int32)
98{
99 m_value.as_i32 = value;
100}
101
102Variant::Variant(i64 value)
103 : m_type(Type::Int64)
104{
105 m_value.as_i64 = value;
106}
107
108Variant::Variant(unsigned value)
109 : m_type(Type::UnsignedInt)
110{
111 m_value.as_uint = value;
112}
113
114Variant::Variant(float value)
115 : m_type(Type::Float)
116{
117 m_value.as_float = value;
118}
119
120Variant::Variant(bool value)
121 : m_type(Type::Bool)
122{
123 m_value.as_bool = value;
124}
125
126Variant::Variant(const char* cstring)
127 : Variant(String(cstring))
128{
129}
130
131Variant::Variant(const String& value)
132 : m_type(Type::String)
133{
134 m_value.as_string = const_cast<StringImpl*>(value.impl());
135 AK::ref_if_not_null(m_value.as_string);
136}
137
138Variant::Variant(const JsonValue& value)
139{
140 if (value.is_null()) {
141 m_value.as_string = nullptr;
142 return;
143 }
144
145 if (value.is_i32()) {
146 m_type = Type::Int32;
147 m_value.as_i32 = value.as_i32();
148 return;
149 }
150
151 if (value.is_u32()) {
152 m_type = Type::UnsignedInt;
153 m_value.as_uint = value.as_u32();
154 return;
155 }
156
157 if (value.is_i64()) {
158 m_type = Type::Int64;
159 m_value.as_i64 = value.as_i64();
160 return;
161 }
162
163 if (value.is_u64()) {
164 // FIXME: Variant should have a 64-bit internal type.
165 m_type = Type::UnsignedInt;
166 m_value.as_uint = value.to_u32();
167 return;
168 }
169
170 if (value.is_string()) {
171 m_type = Type::String;
172 m_value.as_string = value.as_string().impl();
173 m_value.as_string->ref();
174 return;
175 }
176
177 if (value.is_bool()) {
178 m_type = Type::Bool;
179 m_value.as_bool = value.as_bool();
180 return;
181 }
182
183 ASSERT_NOT_REACHED();
184}
185
186Variant::Variant(const Gfx::Bitmap& value)
187 : m_type(Type::Bitmap)
188{
189 m_value.as_bitmap = const_cast<Gfx::Bitmap*>(&value);
190 AK::ref_if_not_null(m_value.as_bitmap);
191}
192
193Variant::Variant(const GIcon& value)
194 : m_type(Type::Icon)
195{
196 m_value.as_icon = &const_cast<GIconImpl&>(value.impl());
197 AK::ref_if_not_null(m_value.as_icon);
198}
199
200Variant::Variant(const Gfx::Font& value)
201 : m_type(Type::Font)
202{
203 m_value.as_font = &const_cast<Gfx::Font&>(value);
204 AK::ref_if_not_null(m_value.as_font);
205}
206
207Variant::Variant(Color color)
208 : m_type(Type::Color)
209{
210 m_value.as_color = color.value();
211}
212
213Variant::Variant(const Gfx::Point& point)
214 : m_type(Type::Point)
215{
216 m_value.as_point = { point.x(), point.y() };
217}
218
219Variant::Variant(const Gfx::Size& size)
220 : m_type(Type::Size)
221{
222 m_value.as_size = { size.width(), size.height() };
223}
224
225Variant::Variant(const Gfx::Rect& rect)
226 : m_type(Type::Rect)
227{
228 m_value.as_rect = (const RawRect&)rect;
229}
230
231Variant& Variant::operator=(const Variant& other)
232{
233 if (&other == this)
234 return *this;
235 clear();
236 copy_from(other);
237 return *this;
238}
239
240Variant& Variant::operator=(Variant&& other)
241{
242 if (&other == this)
243 return *this;
244 // FIXME: Move, not copy!
245 clear();
246 copy_from(other);
247 other.clear();
248 return *this;
249}
250
251Variant::Variant(const Variant& other)
252{
253 copy_from(other);
254}
255
256void Variant::copy_from(const Variant& other)
257{
258 ASSERT(!is_valid());
259 m_type = other.m_type;
260 switch (m_type) {
261 case Type::Bool:
262 m_value.as_bool = other.m_value.as_bool;
263 break;
264 case Type::Int32:
265 m_value.as_i32 = other.m_value.as_i32;
266 break;
267 case Type::Int64:
268 m_value.as_i64 = other.m_value.as_i64;
269 break;
270 case Type::UnsignedInt:
271 m_value.as_uint = other.m_value.as_uint;
272 break;
273 case Type::Float:
274 m_value.as_float = other.m_value.as_float;
275 break;
276 case Type::String:
277 m_value.as_string = other.m_value.as_string;
278 AK::ref_if_not_null(m_value.as_bitmap);
279 break;
280 case Type::Bitmap:
281 m_value.as_bitmap = other.m_value.as_bitmap;
282 AK::ref_if_not_null(m_value.as_bitmap);
283 break;
284 case Type::Icon:
285 m_value.as_icon = other.m_value.as_icon;
286 AK::ref_if_not_null(m_value.as_icon);
287 break;
288 case Type::Font:
289 m_value.as_font = other.m_value.as_font;
290 AK::ref_if_not_null(m_value.as_font);
291 break;
292 case Type::Color:
293 m_value.as_color = other.m_value.as_color;
294 break;
295 case Type::Point:
296 m_value.as_point = other.m_value.as_point;
297 break;
298 case Type::Size:
299 m_value.as_size = other.m_value.as_size;
300 break;
301 case Type::Rect:
302 m_value.as_rect = other.m_value.as_rect;
303 break;
304 case Type::Invalid:
305 break;
306 }
307}
308
309bool Variant::operator==(const Variant& other) const
310{
311 if (m_type != other.m_type)
312 return to_string() == other.to_string();
313 switch (m_type) {
314 case Type::Bool:
315 return as_bool() == other.as_bool();
316 case Type::Int32:
317 return as_i32() == other.as_i32();
318 case Type::Int64:
319 return as_i64() == other.as_i64();
320 case Type::UnsignedInt:
321 return as_uint() == other.as_uint();
322 case Type::Float:
323 return as_float() == other.as_float();
324 case Type::String:
325 return as_string() == other.as_string();
326 case Type::Bitmap:
327 return m_value.as_bitmap == other.m_value.as_bitmap;
328 case Type::Icon:
329 return m_value.as_icon == other.m_value.as_icon;
330 case Type::Color:
331 return m_value.as_color == other.m_value.as_color;
332 case Type::Point:
333 return as_point() == other.as_point();
334 case Type::Size:
335 return as_size() == other.as_size();
336 case Type::Rect:
337 return as_rect() == other.as_rect();
338 case Type::Font:
339 return &as_font() == &other.as_font();
340 case Type::Invalid:
341 return true;
342 }
343 ASSERT_NOT_REACHED();
344}
345
346bool Variant::operator<(const Variant& other) const
347{
348 if (m_type != other.m_type)
349 return to_string() < other.to_string();
350 switch (m_type) {
351 case Type::Bool:
352 return as_bool() < other.as_bool();
353 case Type::Int32:
354 return as_i32() < other.as_i32();
355 case Type::Int64:
356 return as_i64() < other.as_i64();
357 case Type::UnsignedInt:
358 return as_uint() < other.as_uint();
359 case Type::Float:
360 return as_float() < other.as_float();
361 case Type::String:
362 return as_string() < other.as_string();
363 case Type::Bitmap:
364 // FIXME: Maybe compare bitmaps somehow differently?
365 return m_value.as_bitmap < other.m_value.as_bitmap;
366 case Type::Icon:
367 // FIXME: Maybe compare icons somehow differently?
368 return m_value.as_icon < other.m_value.as_icon;
369 case Type::Color:
370 return m_value.as_color < other.m_value.as_color;
371 case Type::Point:
372 case Type::Size:
373 case Type::Rect:
374 case Type::Font:
375 // FIXME: Figure out how to compare these.
376 ASSERT_NOT_REACHED();
377 case Type::Invalid:
378 break;
379 }
380 ASSERT_NOT_REACHED();
381}
382
383String Variant::to_string() const
384{
385 switch (m_type) {
386 case Type::Bool:
387 return as_bool() ? "true" : "false";
388 case Type::Int32:
389 return String::number(as_i32());
390 case Type::Int64:
391 return String::number(as_i64());
392 case Type::UnsignedInt:
393 return String::number(as_uint());
394 case Type::Float:
395 return String::format("%f", (double)as_float());
396 case Type::String:
397 return as_string();
398 case Type::Bitmap:
399 return "[Gfx::Bitmap]";
400 case Type::Icon:
401 return "[GIcon]";
402 case Type::Color:
403 return as_color().to_string();
404 case Type::Point:
405 return as_point().to_string();
406 case Type::Size:
407 return as_size().to_string();
408 case Type::Rect:
409 return as_rect().to_string();
410 case Type::Font:
411 return String::format("[Font: %s]", as_font().name().characters());
412 case Type::Invalid:
413 return "[null]";
414 break;
415 }
416 ASSERT_NOT_REACHED();
417}
418
419}