drawing in a TreeView



I'm trying to draw a box in a TreeView cell and after struggling with
it for a couple days, I'm finally ready to ask for help.  What I want
to do is have a TreeView which contains a list of colors.  Each item
would have a small box (colorswatch) which displays the color, as well
as a string representation of the color (i.e. "#FFFFFF").

[See a mockup here:
http://download.gna.org/colorscheme/screenshots/devel/treeview-mockup.png]

I've tried to create a custom cell renderer to do this, but have had a
lot of trouble finding anything decent to reference.  The thing I've
been working with most is the MyCellRendererToggle example from gtkmm
cvs (http://cvs.gnome.org/viewcvs/gtkmm/examples/cellrenderercustom/cellrenderertoggle.cc?rev=1.4),
but this only gets me so far since there's no comments or
documentation and the goal is somewhat different than what I'm trying
to do.

Here's what I've got for my custom CellRenderer so far (mostly
borrowed from the MyCellRendererToggle example listed above):
/////////////////////////////////////////////////////////////////////////////

        class CellRendererSwatch : public Gtk::CellRenderer
        {
            public:
                CellRendererSwatch(void);
                virtual ~CellRendererSwatch(void);

                // The size of the color swatch
                inline Glib::PropertyProxy<gint>
                    property_size(void) { return m_property_size.get_proxy(); }

                // The color of the color swatch
                inline Glib::PropertyProxy<tHexString>
                    property_color(void) { return
m_property_color.get_proxy(); }

                // The line-width of the border of the swatch
                inline Glib::PropertyProxy<gint>
                    property_border_width(void) { return
                        m_property_border_width.get_proxy(); }

                // The color of the border around the swatch
                inline Glib::PropertyProxy<tHexString>
                    property_border_color(void) { return
                        m_property_border_color.get_proxy(); }

            protected:
                virtual void get_size_vfunc(Gtk::Widget& widget,
                        const Gdk::Rectangle* cell_area,
                        int* x_offset, int* y_offset,
                        int* width, int* height);

                virtual void render_vfunc(
                        const Glib::RefPtr<Gdk::Drawable>& window,
                        Gtk::Widget& widget,
                        const Gdk::Rectangle& background_area,
                        const Gdk::Rectangle& cell_area,
                        const Gdk::Rectangle& expose_area,
                        Gtk::CellRendererState flags);

            private:
                Glib::Property<gint> m_property_size;
                Glib::Property<tHexString> m_property_color;
                Glib::Property<gint> m_property_border_width;
                Glib::Property<tHexString> m_property_border_color;

        };
///////////////////////////////////////////////////////////////////////////
// The implementation is as follows

        CellRendererSwatch::CellRendererSwatch(void) :
            Glib::ObjectBase(typeid(CellRendererSwatch)),
            Gtk::CellRenderer(),
            m_property_size(*this, "size", 12),
            m_property_color(*this, "color", "#FFFFFF"),
            m_property_border_width(*this, "border-width", 1),
            m_property_border_color(*this, "border-color", "#000000")
        {
            property_xpad() = 2;
            property_ypad() = 2;
        }


        void CellRendererSwatch::get_size_vfunc(Gtk::Widget& widget,
                const Gdk::Rectangle* cell_area,
                int* x_offset, int* y_offset,
                int* width, int* height)
        {
            if (width)
            {
                *width = 2 * property_xpad() + property_size();
            }

            if (height)
            {
                *height = 2 * property_ypad() + property_size();
            }

            if (cell_area)
            {
                if (x_offset)
                {
                    // property_xalign() can be between 0 and 1, inclusive
                    *x_offset = static_cast<int>(property_xalign() *
                            (cell_area->get_width() - *width));
                    *x_offset = std::max(0, *x_offset);
                }

                if (y_offset)
                {
                    *y_offset = static_cast<int>(property_yalign() *
                            (cell_area->get_height() - *height));
                    *y_offset = std::max(0, *y_offset);
                }
            }
        }


        void CellRendererSwatch::render_vfunc(
                const Glib::RefPtr<Gdk::Drawable>& window,
                Gtk::Widget& widget,
                const Gdk::Rectangle& background_area,
                const Gdk::Rectangle& cell_area,
                const Gdk::Rectangle& expose_area,
                Gtk::CellRendererState flags)
        {
            const unsigned int cell_xpad = property_xpad();
            const unsigned int cell_ypad = property_ypad();

            int x_offset = 0, y_offset = 0, width = 0, height = 0;
            get_size(widget, cell_area, x_offset, y_offset, width, height);

            width -= cell_xpad * 2;
            height -= cell_ypad * 2;

            if (width <= 0 || height <= 0)
                return;

            Gtk::StateType state = Gtk::STATE_INSENSITIVE;

            if (flags & Gtk::CELL_RENDERER_SELECTED != 0)
            {
                state = (widget.has_focus())
                    ? Gtk::STATE_SELECTED
                    : Gtk::STATE_ACTIVE;
            }

            if(window)
            {
                window->draw_rectangle(widget.get_style()->get_black_gc(),
                        true, cell_area.get_x(),// + x_offset + cell_xpad,
                        cell_area.get_y(),// + y_offset + cell_ypad,
                        width, height);
            }
        }

        CellRendererSwatch::~CellRendererSwatch(void)
        {}


///////////////////////////////////////////////////////////////////////////////////
// Then in my TreeView implementation (constructor), I have the following

            CellRendererSwatch *const pRenderer = Gtk::manage(new
                    CellRendererSwatch);
            Gtk::TreeViewColumn *const pColumn = Gtk::manage(new
                    Gtk::TreeViewColumn("", *pRenderer));
            append_column(*pColumn);
            pColumn->add_attribute(pRenderer->property_color(),
                    m_columns.m_colText);
            append_column("Favorites", m_columns.m_colText);

////////////////////////////////////////////////////////// END
//////////////////////////////////

Everything compiles fine, but where I expect a rectangle to be drawn,
there's absolutely nothing.  I have no idea if I'm even approaching
the problem correctly.  Since most of the implementation is the same
as the given example, I'm fairly sure the issue must be in the
render_vfunc since it's the only function that's significantly
different.  I have no idea whether it's even legal to just draw a
rectangle on the window passed into render_vfunc or if I'm doing
something extremely stupid.  Can anybody give any advice on this
topic?  If I can get this figured out, I'd be willing to contribute
some of my findings back to the gtkmm documentation as well.

Thanks, 
Jonathon


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]