Serenity Operating System
at hosted 425 lines 11 kB view raw
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}