diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-03-24 04:28:36 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-03-24 04:28:36 +0100 |
commit | 86413a6f5a47593e78daaeca1d1af3def527b1d0 (patch) | |
tree | 9df2b5055b92d064e13852ac65405724658bfcfc /LibGUI | |
parent | 7e54fdce996ef520624667ccc2c559b2cc5d6826 (diff) | |
download | serenity-86413a6f5a47593e78daaeca1d1af3def527b1d0.zip |
LibGUI+FileManager: Add a GIcon class to support multi-size icons.
A GIcon can contain any number of bitmaps internally, and will give you
the best fitting icon when you call bitmap_for_size().
Diffstat (limited to 'LibGUI')
-rw-r--r-- | LibGUI/GIcon.cpp | 63 | ||||
-rw-r--r-- | LibGUI/GIcon.h | 41 | ||||
-rw-r--r-- | LibGUI/GItemView.cpp | 5 | ||||
-rw-r--r-- | LibGUI/GTableView.cpp | 3 | ||||
-rw-r--r-- | LibGUI/GVariant.cpp | 18 | ||||
-rw-r--r-- | LibGUI/GVariant.h | 11 | ||||
-rw-r--r-- | LibGUI/Makefile | 1 |
7 files changed, 140 insertions, 2 deletions
diff --git a/LibGUI/GIcon.cpp b/LibGUI/GIcon.cpp new file mode 100644 index 0000000000..16224f1a97 --- /dev/null +++ b/LibGUI/GIcon.cpp @@ -0,0 +1,63 @@ +#include <LibGUI/GIcon.h> + +GIcon::GIcon() + : m_impl(GIconImpl::create()) +{ +} + +GIcon::GIcon(const GIconImpl& impl) + : m_impl(const_cast<GIconImpl&>(impl)) +{ +} + +GIcon::GIcon(const GIcon& other) + : m_impl(other.m_impl.copy_ref()) +{ +} + +GIcon::GIcon(RetainPtr<GraphicsBitmap>&& bitmap) + : GIcon() +{ + if (bitmap) { + ASSERT(bitmap->width() == bitmap->height()); + int size = bitmap->width(); + set_bitmap_for_size(size, move(bitmap)); + } +} + +GIcon::GIcon(RetainPtr<GraphicsBitmap>&& bitmap1, RetainPtr<GraphicsBitmap>&& bitmap2) + : GIcon(move(bitmap1)) +{ + if (bitmap2) { + ASSERT(bitmap2->width() == bitmap2->height()); + int size = bitmap2->width(); + set_bitmap_for_size(size, move(bitmap2)); + } +} + +const GraphicsBitmap* GIconImpl::bitmap_for_size(int size) const +{ + auto it = m_bitmaps.find(size); + if (it != m_bitmaps.end()) + return it->value.ptr(); + + int best_diff_so_far = INT32_MAX; + const GraphicsBitmap* best_fit = nullptr; + for (auto& it : m_bitmaps) { + int abs_diff = abs(it.key - size); + if (abs_diff < best_diff_so_far) { + best_diff_so_far = abs_diff; + best_fit = it.value.ptr(); + } + } + return best_fit; +} + +void GIconImpl::set_bitmap_for_size(int size, RetainPtr<GraphicsBitmap>&& bitmap) +{ + if (!bitmap) { + m_bitmaps.remove(size); + return; + } + m_bitmaps.set(size, move(bitmap)); +} diff --git a/LibGUI/GIcon.h b/LibGUI/GIcon.h new file mode 100644 index 0000000000..bfb48496ba --- /dev/null +++ b/LibGUI/GIcon.h @@ -0,0 +1,41 @@ +#pragma once + +#include <SharedGraphics/GraphicsBitmap.h> +#include <AK/HashMap.h> + +class GIconImpl : public Retainable<GIconImpl> { +public: + static Retained<GIconImpl> create() { return adopt(*new GIconImpl); } + ~GIconImpl() { } + + const GraphicsBitmap* bitmap_for_size(int) const; + void set_bitmap_for_size(int, RetainPtr<GraphicsBitmap>&&); + +private: + GIconImpl() { } + HashMap<int, RetainPtr<GraphicsBitmap>> m_bitmaps; +}; + +class GIcon { +public: + GIcon(); + explicit GIcon(RetainPtr<GraphicsBitmap>&&); + explicit GIcon(RetainPtr<GraphicsBitmap>&&, RetainPtr<GraphicsBitmap>&&); + explicit GIcon(const GIconImpl&); + GIcon(const GIcon&); + ~GIcon() { } + + GIcon& operator=(const GIcon& other) + { + m_impl = other.m_impl.copy_ref(); + return *this; + } + + const GraphicsBitmap* bitmap_for_size(int size) const { return m_impl->bitmap_for_size(size); } + void set_bitmap_for_size(int size, RetainPtr<GraphicsBitmap>&& bitmap) { m_impl->set_bitmap_for_size(size, move(bitmap)); } + + const GIconImpl& impl() const { return *m_impl; } + +private: + Retained<GIconImpl> m_impl; +}; diff --git a/LibGUI/GItemView.cpp b/LibGUI/GItemView.cpp index db0499c121..39c2f2cb04 100644 --- a/LibGUI/GItemView.cpp +++ b/LibGUI/GItemView.cpp @@ -110,8 +110,9 @@ void GItemView::paint_event(GPaintEvent& event) icon_rect.center_within(item_rect); icon_rect.move_by(0, -font.glyph_height() - 6); - if (icon.is_bitmap()) { - painter.draw_scaled_bitmap(icon_rect, icon.as_bitmap(), icon.as_bitmap().rect()); + if (icon.is_icon()) { + if (auto bitmap = icon.as_icon().bitmap_for_size(icon_rect.width())) + painter.draw_scaled_bitmap(icon_rect, *bitmap, bitmap->rect()); } Rect text_rect { 0, icon_rect.bottom() + 6 + 1, font.width(item_text.to_string()), font.glyph_height() }; diff --git a/LibGUI/GTableView.cpp b/LibGUI/GTableView.cpp index e753002ab7..81797be626 100644 --- a/LibGUI/GTableView.cpp +++ b/LibGUI/GTableView.cpp @@ -141,6 +141,9 @@ void GTableView::paint_event(GPaintEvent& event) auto data = model()->data(cell_index); if (data.is_bitmap()) { painter.blit(cell_rect.location(), data.as_bitmap(), data.as_bitmap().rect()); + } else if (data.is_icon()) { + if (auto bitmap = data.as_icon().bitmap_for_size(16)) + painter.blit(cell_rect.location(), *bitmap, bitmap->rect()); } else { Color text_color; if (is_selected_row) diff --git a/LibGUI/GVariant.cpp b/LibGUI/GVariant.cpp index 1e8b7d187a..6f9d62a620 100644 --- a/LibGUI/GVariant.cpp +++ b/LibGUI/GVariant.cpp @@ -15,6 +15,10 @@ GVariant::~GVariant() if (m_value.as_bitmap) m_value.as_bitmap->release(); break; + case Type::Icon: + if (m_value.as_icon) + m_value.as_icon->release(); + break; default: break; } @@ -52,6 +56,13 @@ GVariant::GVariant(const GraphicsBitmap& value) AK::retain_if_not_null(m_value.as_bitmap); } +GVariant::GVariant(const GIcon& value) + : m_type(Type::Icon) +{ + m_value.as_icon = &const_cast<GIconImpl&>(value.impl()); + AK::retain_if_not_null(m_value.as_icon); +} + GVariant::GVariant(Color color) : m_type(Type::Color) { @@ -73,6 +84,8 @@ bool GVariant::operator==(const GVariant& other) const return as_string() == other.as_string(); case Type::Bitmap: return m_value.as_bitmap == other.m_value.as_bitmap; + case Type::Icon: + return m_value.as_icon == other.m_value.as_icon; case Type::Color: return m_value.as_color == other.m_value.as_color; case Type::Invalid: @@ -97,6 +110,9 @@ bool GVariant::operator<(const GVariant& other) const case Type::Bitmap: // FIXME: Maybe compare bitmaps somehow differently? return m_value.as_bitmap < other.m_value.as_bitmap; + case Type::Icon: + // FIXME: Maybe compare icons somehow differently? + return m_value.as_icon < other.m_value.as_icon; case Type::Color: return m_value.as_color < other.m_value.as_color; case Type::Invalid: @@ -118,6 +134,8 @@ String GVariant::to_string() const return as_string(); case Type::Bitmap: return "[GraphicsBitmap]"; + case Type::Icon: + return "[GIcon]"; case Type::Color: return as_color().to_string(); case Type::Invalid: diff --git a/LibGUI/GVariant.h b/LibGUI/GVariant.h index 1346188015..3631c6e581 100644 --- a/LibGUI/GVariant.h +++ b/LibGUI/GVariant.h @@ -1,6 +1,7 @@ #pragma once #include <AK/AKString.h> +#include <LibGUI/GIcon.h> #include <SharedGraphics/GraphicsBitmap.h> class GVariant { @@ -11,6 +12,7 @@ public: GVariant(int); GVariant(const String&); GVariant(const GraphicsBitmap&); + GVariant(const GIcon&); GVariant(Color); ~GVariant(); @@ -22,6 +24,7 @@ public: String, Bitmap, Color, + Icon, }; bool is_valid() const { return m_type != Type::Invalid; } @@ -31,6 +34,7 @@ public: bool is_string() const { return m_type == Type::String; } bool is_bitmap() const { return m_type == Type::Bitmap; } bool is_color() const { return m_type == Type::Color; } + bool is_icon() const { return m_type == Type::Icon; } Type type() const { return m_type; } bool as_bool() const @@ -63,6 +67,12 @@ public: return *m_value.as_bitmap; } + GIcon as_icon() const + { + ASSERT(type() == Type::Icon); + return GIcon(*m_value.as_icon); + } + Color as_color() const { ASSERT(type() == Type::Color); @@ -85,6 +95,7 @@ private: union { StringImpl* as_string; GraphicsBitmap* as_bitmap; + GIconImpl* as_icon; bool as_bool; int as_int; float as_float; diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 1cd0beaf53..6d67ef550f 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -50,6 +50,7 @@ LIBGUI_OBJS = \ GProgressBar.o \ GAbstractView.o \ GItemView.o \ + GIcon.o \ GWindow.o OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS) |