Hi, I am trying to use Gtk::Layout to implement a layout widget in which number of child widgets (of fixed size) in a row depends on the size of the layout widget. If the layout widget is expanded/reduced the number of widgets displayed in the row should increase/decrease accordingly. Very similar to what file browsers do. But I ain't able to get the Layout widget displayed at all. I have attached a minimal source and screenshots of the program. Would appreciate if someone could tell whats going wrong here or some other way to do the same. Thanks in advance. Ram P.S. There hasn't been much activity on this group in the last few days. I hope it hasn't been moved elsewhere.
Attachment:
layout.jpg
Description: JPEG image
#include "navigationview.h" #include <algorithm> #include <iostream> #include <functional> namespace Ui { NavigationView::NavigationView(int cw, int ch, int padding): m_ChildWidth(cw), m_ChildHeight(ch), m_Padding(padding) { init(); } NavigationView::~NavigationView() { } void NavigationView::insert(ChildListT::iterator pos, Gtk::Widget *wptr) { m_ChildList.insert(pos, wptr); wptr->set_parent(*this); update_layout(); } void NavigationView::erase(ChildListT::iterator pos) { (*pos)->unparent(); m_ChildList.erase(pos); update_layout(); } void NavigationView::clear() { std::for_each(m_ChildList.begin(), m_ChildList.end(), std::mem_fun(&Gtk::Widget::unparent)); m_ChildList.clear(); update_layout(); } void NavigationView::init() { m_ChildWidth = std::max(1, m_ChildWidth); m_ChildHeight = std::max(1, m_ChildHeight); m_Padding = std::max(1, m_Padding); update_layout(); show_all_children(); } void NavigationView::update_layout() { update_layout(get_allocation()); } void NavigationView::update_layout(const Gtk::Allocation &allocation) { std::cout << "update layout\n"; // calculate screen parameters, number of rows, columns to be displayed int avail_width = allocation.get_width() - 2*BORDER_SIZE; m_CellWidth = m_ChildWidth + 2*m_Padding; m_CellHeight = m_ChildHeight + 2*m_Padding; m_NumCols = std::max(1, avail_width/m_CellWidth); m_NumRows = m_ChildList.size()/m_NumCols; if(m_ChildList.size() % m_NumCols != 0) ++m_NumRows; int height = m_NumRows*m_CellHeight + 2*BORDER_SIZE; get_vadjustment()->set_step_increment(m_CellHeight); int x = int(get_hadjustment()->get_value()); int y = int(height*m_ScrollValue); int index = 0; ChildListT::iterator it; for(it = m_ChildList.begin(); it != m_ChildList.end(); ++it, ++index) { int ccol = index % m_NumCols; int crow = index / m_NumCols; int cx = BORDER_SIZE + m_Padding + ccol*m_CellWidth; int cy = BORDER_SIZE + m_Padding + crow*m_CellHeight; Gtk::Allocation child_alloc(cx, cy, m_ChildWidth, m_ChildHeight); (*it)->size_allocate(child_alloc); } set_size(x, y, allocation.get_width(), height); show_all_children(); } void NavigationView::set_size(int x, int y, int width, int height) { get_hadjustment()->set_upper(std::max(get_allocation().get_width(), width)); get_vadjustment()->set_upper(std::max(get_allocation().get_height(), height)); bool xchange = get_hadjustment()->get_value() != x; bool ychange = get_vadjustment()->get_value() != y; if(xchange || ychange) { get_hadjustment()->set_value(x); get_vadjustment()->set_value(y); } if(get_width() != width || get_height() != height) BaseT::set_size(width, height); } /* bool NavigationView::on_expose_event(GdkEventExpose *event) { Gdk::Rectangle area(&(event->area)); draw_all_cells(area); return BaseT::on_expose_event(event); } */ void NavigationView::draw_all_cells(const Gdk::Rectangle &area) { // This is an in-efficient way of updating, we need only update cells // lying in area std::cout << "drawing..\n"; show_all_children(); for(ChildListT::iterator it = m_ChildList.begin(); it != m_ChildList.end(); ++it) { (*it)->show(); (*it)->queue_draw(); } } void NavigationView::on_size_allocate(Gtk::Allocation &allocation) { std::cout << "alloc.w: " << allocation.get_width() << ", " << "alloc.h: " << allocation.get_height() << "\n"; m_ScrollValue = (get_vadjustment()->get_value()/get_vadjustment()->get_upper()); update_layout(allocation); set_allocation(allocation); // should I call base version, it doesn't seem to make any difference :( BaseT::on_size_allocate(allocation); } void NavigationView::on_size_request(Gtk::Requisition *requis) { *requis = Gtk::Requisition(); // sensible minimums requis->width = 300; requis->height = 200; } } /* namespace Ui */
#ifndef _UI_NAVIGATIONVIEW_H_ #define _UI_NAVIGATIONVIEW_H_ #include <gtkmm/table.h> #include <gtkmm/layout.h> #include <list> namespace Ui { class NavigationView: public Gtk::Layout { public: typedef std::list<Widget*> ChildListT; public: // (cwidth, cheight) => child width and height (fixed) NavigationView(int cwidth, int cheight, int padding = 1); virtual ~NavigationView(); bool empty() const { return m_ChildList.empty(); } void child_width(int cwidth) { m_ChildWidth = cwidth; } void child_height(int cheight) { m_ChildHeight = cheight; } int child_width() const { return m_ChildWidth; } int child_height() const { return m_ChildHeight; } ChildListT::iterator begin() { return m_ChildList.begin(); } ChildListT::iterator end() { return m_ChildList.end(); } // insertion void insert(ChildListT::iterator pos, Gtk::Widget *wptr); // removal void erase(ChildListT::iterator pos); void clear(); protected: typedef Gtk::Layout BaseT; // data int m_ChildWidth, m_ChildHeight; int m_Padding; ChildListT m_ChildList; int m_CellWidth, m_CellHeight; int m_HSize, m_VSize; double m_ScrollValue; int m_NumRows, m_NumCols; static const int BORDER_SIZE = 6; // overrides virtual void on_size_allocate(Gtk::Allocation &allocation); virtual void on_size_request(Gtk::Requisition *requis); // virtual bool on_expose_event(GdkEventExpose *event); // virtual void init(); virtual void update_layout(); virtual void update_layout(const Gtk::Allocation &allocation); virtual void set_size(int x, int y, int w, int h); virtual void draw_all_cells(const Gdk::Rectangle &area); }; } /* namespace Ui */ #endif /* _UI_NAVIGATIONVIEW_H_ */
#include "navigationview.h" #include <gtkmm/main.h> #include <gtkmm/button.h> #include <gtkmm/window.h> #include <gtkmm/box.h> #include <iostream> #include <string> #include <sstream> #include <boost/shared_ptr.hpp> using namespace std; Glib::ustring str(int i) { ostringstream out; out << i; return out.str(); } class ExampleWindow: public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); protected: //Child widgets: Ui::NavigationView m_View; std::list< boost::shared_ptr<Gtk::Button> > m_BList; void init(int count); void on_change(); }; ExampleWindow::ExampleWindow(): m_View(20, 20) { Gtk::VBox *pbox= Gtk::manage(new Gtk::VBox); Gtk::Button *pchange = Gtk::manage(new Gtk::Button("_Resize", true)); add(*pbox); init(10); pbox->pack_start(m_View); pbox->pack_start(*pchange); pchange->signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_change)); show_all_children(); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_change() { cout << "resizing to " << m_BList.size() + 1 << endl; init(m_BList.size() + 1); } void ExampleWindow::init(int count) { Gtk::Button *bptr = new Gtk::Button(str(m_BList.size())); m_BList.push_back(boost::shared_ptr<Gtk::Button>(bptr)); m_View.insert(m_View.end(), bptr); } #include <gtkmm/main.h> int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); ExampleWindow window; kit.run(window); //Shows the window and returns when it is closed. return 0; }