summaryrefslogtreecommitdiff
path: root/LibGUI
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-03-24 04:28:36 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-03-24 04:28:36 +0100
commit86413a6f5a47593e78daaeca1d1af3def527b1d0 (patch)
tree9df2b5055b92d064e13852ac65405724658bfcfc /LibGUI
parent7e54fdce996ef520624667ccc2c559b2cc5d6826 (diff)
downloadserenity-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.cpp63
-rw-r--r--LibGUI/GIcon.h41
-rw-r--r--LibGUI/GItemView.cpp5
-rw-r--r--LibGUI/GTableView.cpp3
-rw-r--r--LibGUI/GVariant.cpp18
-rw-r--r--LibGUI/GVariant.h11
-rw-r--r--LibGUI/Makefile1
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)