← Back to team overview

millennium-dev team mailing list archive

[Merge] lp:~rafalcieslak256/millenniumduel/containers into lp:millenniumduel

 

Rafał Cieślak has proposed merging lp:~rafalcieslak256/millenniumduel/containers into lp:millenniumduel.

Requested reviews:
  Adam Malinowski (adayah)
  Millennium Developers (millennium-dev)

For more details, see:
https://code.launchpad.net/~rafalcieslak256/millenniumduel/containers/+merge/176052

This branch implements Container widgets (namely a custom VBox and a HBox).
[https://blueprints.launchpad.net/millenniumduel/+spec/millenniumduel-containers]

These widgets are meant to spread evenly widgets aligned horizontally or vertically.

They are kind of similar to GTK's boxes, but one should not assume any similarities.

This branch also significantly changes the way draw() is used. It is now called with a set of 4 values, representing coordinates of a rectangular area where the widget should draw itself.
This way all widgets can be drawn in variety of sizes.

All Drawables can also provide the minimal size they need for drawing (for example, a button cannot be too thin or its text will not fit). These can be learned by calling GetMinimalHeight and GetMinimalWidth.

Both boxes are used by appending widgets with Add(drawable). By default all items are shrinked to minimum, except for those that are added with BOX_EXPAND as a second argument to Add, these will be spread evenly.
One can set the space between boxes with SetSpacing, as well as the margin around the Box with SetMargin (both default to 0).

Of course, Boxes are also a Drawable, and therefore can be nested freely.

Another change introduced by this branch is that a View widget (renamed to Fixed) is now a Drawable.
The Display class requires now a Drawable to be the topmost widget, it does not have to be a Fixed (View).

The example in main() sets a VBox as the main menu, shrinking and expanding some of the buttons. The additional menu is left as it was, as a Fixed.

NOTE: This code does not fix bug #1198640.
-- 
https://code.launchpad.net/~rafalcieslak256/millenniumduel/containers/+merge/176052
Your team Millennium Developers is requested to review the proposed merge of lp:~rafalcieslak256/millenniumduel/containers into lp:millenniumduel.
=== added file 'src/Box.cpp'
--- src/Box.cpp	1970-01-01 00:00:00 +0000
+++ src/Box.cpp	2013-07-21 13:05:30 +0000
@@ -0,0 +1,59 @@
+#include "Box.hpp"
+
+Box::Box(){
+    spacing = 0;
+    margin = 0;
+}
+
+void Box::_RecalculateSizes(int total, int (Drawable::*size_func)()){
+    if(children.size() == 0) return;
+
+    int shrinked_sum = 0;
+    int expand_count = 0;
+    
+    for(auto &i : children){
+        if(i.mode == BOX_SHRINK){
+            int h = ((i.item).*size_func)(); //use the size_func to get minimal width/height
+            i.size = h;
+            shrinked_sum += h;
+        }else if(i.mode == BOX_EXPAND){
+            expand_count++;
+        }
+        shrinked_sum += spacing;
+    }
+    if (shrinked_sum > 0) shrinked_sum -= spacing;
+    
+    if(expand_count > 0){
+        int rest = total - 2*margin - shrinked_sum;
+        int expand_size = rest / expand_count;
+        int last_expand_size = rest - (expand_size * expand_count) + expand_size;
+        
+        if(expand_size < 0) expand_size = 0;
+        if(last_expand_size < 0) last_expand_size = 0;
+        
+        for(auto &i : children){
+            if(i.mode == BOX_EXPAND){
+                if(expand_count != 1){ //this is not the last expanding item
+                    i.size = expand_size;
+                }else{
+                    i.size = last_expand_size;
+                }
+                expand_count--;
+            }
+        }
+    }
+}
+
+void Box::Add(Drawable& item, int position, BoxPackingMode mode){
+    BoxEntry be(item);
+    be.order = position;
+    be.mode = mode;
+    children.insert(be);
+}
+
+void Box::SetSpacing(int s){
+    spacing = s;
+}
+void Box::SetMargin(int m){
+     margin = m;
+}

=== added file 'src/Box.hpp'
--- src/Box.hpp	1970-01-01 00:00:00 +0000
+++ src/Box.hpp	2013-07-21 13:05:30 +0000
@@ -0,0 +1,47 @@
+#include "drawable.hpp"
+#include <string>
+#include <set>
+
+enum BoxPackingMode{
+    BOX_SHRINK = 0,
+    BOX_EXPAND = 1
+};
+    
+class Box : public Drawable{
+protected:
+    Box();
+    
+public:
+    void Add(Drawable& item, int position, BoxPackingMode mode = BOX_SHRINK);
+    
+    void SetSpacing(int spacing);
+    void SetMargin(int margin);
+    
+    virtual void draw(SDrawArea a) = 0;
+    
+    virtual int GetMinimalHeight() = 0;
+    virtual int GetMinimalWidth () = 0;
+    
+    virtual void on_clicked(SCoordinates p) = 0;
+protected:
+
+    struct BoxEntry{
+        BoxEntry(Drawable& i) : item(i) {};
+        int order; // Used to determine item's position within the container
+        BoxPackingMode mode;
+        mutable int size; // size in px for this item, used temporarily for calculations
+        Drawable& item;
+    };
+    struct BoxEntryComparator{
+        bool operator()(const BoxEntry& x,const BoxEntry& y) const {return x.order < y.order;}
+    };
+    
+    /* This set contains all widgets contained within this container. */
+    std::set< BoxEntry, BoxEntryComparator> children;
+    
+    int spacing;
+    int margin;
+    int current_width, current_height;
+    
+    void _RecalculateSizes(int total, int (Drawable::*size_func)());
+};

=== renamed file 'src/view.cpp' => 'src/Fixed.cpp'
--- src/view.cpp	2013-07-07 08:48:44 +0000
+++ src/Fixed.cpp	2013-07-21 13:05:30 +0000
@@ -1,39 +1,37 @@
-#include "view.hpp"
-#include <allegro5/allegro.h>
-
-void View::draw(){
-    al_clear_to_color(al_map_rgb(0,0,0));
-
-    ALLEGRO_TRANSFORM transform;
+#include "Fixed.hpp"
+
+Fixed::Fixed(int w, int h) : width(w), height(h){
+}
+
+void Fixed::draw(SDrawArea a){
     for(auto q : items){
         Drawable* x = q.first;
-        Coordinates c = q.second;
-        al_identity_transform(&transform);
-        al_translate_transform(&transform, c.x, c.y);
-        al_use_transform(&transform);
+        SCoordinates c = q.second;
 
-        x->draw();
+        int width  = x->GetMinimalWidth ();
+        int height = x->GetMinimalHeight();
+        
+        x->draw(SDrawArea(a.x + c.x, a.y + c.y, width, height));
     }
-    
-    al_identity_transform(&transform);
-    al_use_transform(&transform);
-
-}
-
-void View::add_item(Drawable* d, Coordinates c){
-    items[d] = c;
-}
-
-void View::remove_item(Drawable *d){
-    items.erase(d);
-}
-
-void View::on_clicked(int x, int y){
+}
+
+void Fixed::add_item(Drawable& d, SCoordinates c){
+    items[&d] = c;
+}
+
+void Fixed::remove_item(Drawable& d){
+    items.erase(&d);
+}
+
+void Fixed::on_clicked(SCoordinates p){
     for(auto q : items){
         Drawable* d = q.first;
-        Coordinates c = q.second;
-        if(c.x <= x && c.y <= y && c.x+d->width >= x && c.y+d->height >= y){
-            d->on_clicked();
+        SCoordinates c = q.second;
+        if(c.x <= p.x && c.y <= p.y && c.x+d->GetMinimalWidth() >= p.x && c.y+d->GetMinimalHeight() >= p.y){
+            d->on_clicked(SCoordinates(p.x - c.x, p.y - c.y));
         }
     }
 }
+
+int Fixed::GetMinimalHeight(){ return height; }
+int Fixed::GetMinimalWidth() { return width;  }

=== renamed file 'src/view.hpp' => 'src/Fixed.hpp'
--- src/view.hpp	2013-07-07 08:48:44 +0000
+++ src/Fixed.hpp	2013-07-21 13:05:30 +0000
@@ -1,23 +1,24 @@
-#ifndef __VIEW_HPP__
-#define __VIEW_HPP__
+#ifndef __FIXED_HPP__
+#define __FIXED_HPP__
 
 #include "drawable.hpp"
 #include <map>
 
-struct Coordinates{
-    int x;
-    int y;
-    Coordinates(int _x, int _y) : x(_x), y(_y) {}
-    Coordinates() : x(0), y(0) {}
-};
-
-class View{
+class Fixed : public Drawable{
 public:
-    std::map<Drawable*,Coordinates> items;
-    void draw();
-    void add_item(Drawable* d, Coordinates c);
-    void remove_item(Drawable * d);
-    void on_clicked(int x, int y);
+    Fixed(int w = 0, int h = 0);
+    void draw(SDrawArea a);
+    void add_item(Drawable& d, SCoordinates c);
+    void remove_item(Drawable& d);
+    void on_clicked(SCoordinates y);
+    
+    virtual int GetMinimalWidth () override;
+    virtual int GetMinimalHeight() override;
+private:
+    std::map<Drawable*,SCoordinates> items;
+    
+    int width;
+    int height;
 };
 
-#endif //__VIEW_HPP__
+#endif //__FIXED_HPP__

=== added file 'src/HBox.cpp'
--- src/HBox.cpp	1970-01-01 00:00:00 +0000
+++ src/HBox.cpp	2013-07-21 13:05:30 +0000
@@ -0,0 +1,61 @@
+#include "HBox.hpp"
+
+void HBox::draw(SDrawArea a){
+    
+    _RecalculateSizes(a.h, &Drawable::GetMinimalWidth);
+
+    int x = a.x + margin, y = a.y + margin;
+    
+    for(auto i : children){
+        int width  = i.size;
+        int height = a.h - 2*margin;
+        
+        
+        i.item.draw(SDrawArea(x,y,width,height));
+        
+        x += i.size;
+        x += spacing;
+    }
+    
+    // Remember my size (for click recognition)
+    current_height = a.h;
+    current_width  = a.w;
+    
+}
+
+int HBox::GetMinimalHeight() {
+    // Maximum of all items' heights
+    int max = 0;
+    for(auto i : children){
+        int w = i.item.GetMinimalHeight();
+        if (w > max) max = w;
+    }
+    return max + 2*margin;
+    
+}
+int HBox::GetMinimalWidth () {
+    // Sum of all items' widths and gaps
+    int sum = 0;
+    for(auto i : children){
+        sum += i.item.GetMinimalWidth();
+        sum += spacing;
+    }
+    if(sum >= 0) sum -= spacing;
+    return sum + 2*margin;
+}
+
+void HBox::on_clicked(SCoordinates p){
+    if (p.x < margin || p.y < margin || p.y > current_height - margin) return;
+    int sum = 0;
+    for(auto i : children){
+        sum += i.size;
+        if(p.x <= sum) { // This item was clicked!
+            i.item.on_clicked(SCoordinates(p.x - sum, p.y));
+            return;
+        }
+        sum += spacing;
+        if(p.x <= sum){ // Empty space between items was clicked
+            return;
+        }
+    }
+}

=== added file 'src/HBox.hpp'
--- src/HBox.hpp	1970-01-01 00:00:00 +0000
+++ src/HBox.hpp	2013-07-21 13:05:30 +0000
@@ -0,0 +1,11 @@
+#include "Box.hpp"
+
+class HBox : public Box{
+public:
+    virtual void draw(SDrawArea a) override;
+    
+    virtual int GetMinimalHeight() override;
+    virtual int GetMinimalWidth () override;
+    
+    virtual void on_clicked(SCoordinates p) override;
+};

=== added file 'src/VBox.cpp'
--- src/VBox.cpp	1970-01-01 00:00:00 +0000
+++ src/VBox.cpp	2013-07-21 13:05:30 +0000
@@ -0,0 +1,60 @@
+#include "VBox.hpp"
+
+void VBox::draw(SDrawArea a){
+    
+    _RecalculateSizes(a.h, &Drawable::GetMinimalHeight);
+
+    int x = a.x + margin, y = a.y + margin;
+    
+    for(auto i : children){
+        int width  = a.w - 2*margin;
+        int height = i.size;
+        
+        
+        i.item.draw(SDrawArea(x,y,width,height));
+        
+        y += i.size;
+        y += spacing;
+    }
+    
+    // Remember my size (for click recognition)
+    current_height = a.h;
+    current_width  = a.w;
+    
+}
+
+int VBox::GetMinimalHeight() {
+    // Sum of all items' heights and gaps
+    int sum = 0;
+    for(auto i : children){
+        sum += i.item.GetMinimalHeight();
+        sum += spacing;
+    }
+    if(sum >= 0) sum -= spacing;
+    return sum + 2*margin;
+}
+int VBox::GetMinimalWidth () {
+    // Maximum of all items' widths
+    int max = 0;
+    for(auto i : children){
+        int w = i.item.GetMinimalWidth();
+        if (w > max) max = w;
+    }
+    return max + 2*margin;
+}
+
+void VBox::on_clicked(SCoordinates p){
+    if (p.y < margin || p.x < margin || p.x > current_width - margin) return;
+    int sum = 0;
+    for(auto i : children){
+        sum += i.size;
+        if(p.y <= sum) { // This item was clicked!
+            i.item.on_clicked(SCoordinates(p.x, p.y - sum));
+            return;
+        }
+        sum += spacing;
+        if(p.y <= sum){ // Empty space between items was clicked
+            return;
+        }
+    }
+}

=== added file 'src/VBox.hpp'
--- src/VBox.hpp	1970-01-01 00:00:00 +0000
+++ src/VBox.hpp	2013-07-21 13:05:30 +0000
@@ -0,0 +1,11 @@
+#include "Box.hpp"
+
+class VBox : public Box{
+public:
+    virtual void draw(SDrawArea a) override;
+    
+    virtual int GetMinimalHeight() override;
+    virtual int GetMinimalWidth () override;
+    
+    virtual void on_clicked(SCoordinates p) override;
+};

=== modified file 'src/build'
--- src/build	2013-07-14 19:38:45 +0000
+++ src/build	2013-07-21 13:05:30 +0000
@@ -1,2 +1,2 @@
 #!/bin/sh
-g++-4.8 -o main *.cpp `pkg-config --cflags --libs allegro-5.0 allegro_image-5.0 allegro_primitives-5.0 allegro_font-5.0 allegro_ttf-5.0` --std=c++11
+g++-4.8 -o main *.cpp `pkg-config --cflags --libs allegro-5.0 allegro_image-5.0 allegro_primitives-5.0 allegro_font-5.0 allegro_ttf-5.0` --std=c++11 -Wall -g

=== modified file 'src/button.cpp'
--- src/button.cpp	2013-07-07 08:48:44 +0000
+++ src/button.cpp	2013-07-21 13:05:30 +0000
@@ -5,7 +5,7 @@
 #include <allegro5/allegro_font.h>
 #include <allegro5/allegro_ttf.h>
 
-Button::Button(std::string _text) : Drawable(60,20), text(_text){
+Button::Button(std::string _text) : text(_text){
 
 }
 
@@ -13,13 +13,19 @@
     click_reaction = f;
 }
 
-void Button::draw(){
+void Button::draw(SDrawArea a){
+    use_new_transform_to(a.x,a.y);
     ALLEGRO_COLOR color = al_map_rgb(120, 140, 200);
-    al_draw_filled_rectangle(0,0,width,height, color);
-    al_draw_text(Display::main_font, al_map_rgb(255,255,255), 30, 0 ,ALLEGRO_ALIGN_CENTRE, text.c_str());
+    al_draw_filled_rectangle(0,0, a.w, a.h, color);
+    al_draw_text(Display::main_font, al_map_rgb(255,255,255), a.w/2, a.h/2 - 8, ALLEGRO_ALIGN_CENTRE, text.c_str());
 }
 
 void Button::on_clicked(){
     if(click_reaction == nullptr) return;
     click_reaction();
 }
+
+int Button::GetMinimalHeight() {return 20;}
+int Button::GetMinimalWidth () {
+    return al_get_text_width(Display::main_font, text.c_str()) + 6; // 3px margin from both sides
+}

=== modified file 'src/button.hpp'
--- src/button.hpp	2013-07-07 08:48:44 +0000
+++ src/button.hpp	2013-07-21 13:05:30 +0000
@@ -9,6 +9,9 @@
     void (*click_reaction)() = nullptr;
     std::string text;
     
-    virtual void draw();
-    virtual void on_clicked();
+    virtual void draw(SDrawArea a) override;
+    virtual void on_clicked() override;
+    
+    virtual int GetMinimalHeight() override;
+    virtual int GetMinimalWidth () override;
 };

=== modified file 'src/display.cpp'
--- src/display.cpp	2013-07-07 08:48:44 +0000
+++ src/display.cpp	2013-07-21 13:05:30 +0000
@@ -9,7 +9,7 @@
 
 ALLEGRO_DISPLAY* Display::display      = nullptr; 
 ALLEGRO_FONT*    Display::main_font    = nullptr;
-View*            Display::current_view = nullptr;
+Drawable*        Display::main_widget = nullptr;
 
 void Display::init(){
     al_init();
@@ -18,7 +18,7 @@
     al_init_font_addon();
     al_init_ttf_addon();
    
-    display = al_create_display(200,150);
+    display = al_create_display(170,200);
 
     main_font = al_load_ttf_font("Ubuntu-R.ttf",12,0);
     
@@ -27,10 +27,9 @@
 }
 
 void Display::redraw(){
-    if(current_view != nullptr){
-        current_view->draw();
-    }else{
-        al_clear_to_color(al_map_rgb(0,0,0));
+    al_clear_to_color(al_map_rgb(0,0,0));
+    if(main_widget != nullptr){
+        main_widget->draw( SDrawArea(0,0,al_get_display_width(display),al_get_display_height(display)) );
     }
     al_flip_display();
 }
@@ -56,8 +55,8 @@
             }else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN){
                 int x = ev.mouse.x;
                 int y = ev.mouse.y;
-                if(current_view != nullptr){
-                    current_view->on_clicked(x,y);
+                if(main_widget != nullptr){
+                    main_widget->on_clicked(SCoordinates(x,y));
                 }
             }
         }
@@ -73,6 +72,6 @@
     al_destroy_display(display);
 }
 
-void Display::set_view(View* v){
-    current_view = v;
+void Display::SetMainWidget(Drawable& v){
+    main_widget = &v;
 }

=== modified file 'src/display.hpp'
--- src/display.hpp	2013-07-07 08:48:44 +0000
+++ src/display.hpp	2013-07-21 13:05:30 +0000
@@ -1,7 +1,7 @@
 #ifndef __DISPLAY_HPP__
 #define __DISPLAY_HPP__
 
-#include "view.hpp"
+#include "drawable.hpp"
 #include <allegro5/allegro.h>
 #include <allegro5/allegro_font.h>
 
@@ -11,16 +11,18 @@
     static void main_loop();
     static void cleanup();
 
-    static void set_view(View* v);
+    static void SetMainWidget(Drawable& v);
     
-    static ALLEGRO_DISPLAY* display;
     static ALLEGRO_FONT* main_font;
 
-    static View* current_view;
     
 private:
     Display() = delete;
+    
     static void redraw();
+    
+    static Drawable* main_widget;
+    static ALLEGRO_DISPLAY* display;
 };
 
 #endif //__DISPLAY_HPP__

=== modified file 'src/drawable.cpp'
--- src/drawable.cpp	2013-07-07 08:48:44 +0000
+++ src/drawable.cpp	2013-07-21 13:05:30 +0000
@@ -2,20 +2,30 @@
 #include "allegro5/allegro.h"
 #include "allegro5/allegro_primitives.h"
 #include <iostream>
- 
-Drawable::Drawable(int _w, int _h){
-    width = _w;
-    height = _h;
+
+void Drawable::use_new_transform_to(int x,int y){  
+    ALLEGRO_TRANSFORM temp_transform;
+    al_identity_transform(&temp_transform);
+    al_translate_transform(&temp_transform, x, y);
+    al_use_transform(&temp_transform);
+}
+
+Drawable::Drawable(){
 }
 
 Drawable::~Drawable(){
 }
 
 
-void Drawable::draw(){
+void Drawable::draw(SDrawArea a){
+    use_new_transform_to(a.x,a.y);
     ALLEGRO_COLOR red = al_map_rgb(255, 0, 0);
-    al_draw_filled_rectangle(0,0,width,height, red);
-
+    al_draw_filled_rectangle(0,0, a.w, a.h, red);
+
+}
+
+void Drawable::on_clicked(SCoordinates p){
+    on_clicked(); //by default, use the ignoring position version
 }
 
 void Drawable::on_clicked(){

=== modified file 'src/drawable.hpp'
--- src/drawable.hpp	2013-07-07 08:48:44 +0000
+++ src/drawable.hpp	2013-07-21 13:05:30 +0000
@@ -1,16 +1,38 @@
- #ifndef __DRAWABLE_HPP__
- #define __DRAWABLE_HPP__
- 
- class Drawable{
- public:
-    Drawable(int w, int h);
+#ifndef __DRAWABLE_HPP__
+#define __DRAWABLE_HPP__
+
+struct SDrawArea{
+    SDrawArea(int _x, int _y, int _w, int _h) : x(_x), y(_y), w(_w), h(_h) {};
+    int x;
+    int y;
+    int w;
+    int h;
+};
+
+struct SCoordinates{
+    int x;
+    int y;
+    SCoordinates(int _x, int _y) : x(_x), y(_y) {}
+    SCoordinates() : x(0), y(0) {}
+};
+
+
+class Drawable{
+public:
+    Drawable();
     virtual ~Drawable();
 
-    int width;
-    int height;
+    virtual void draw(SDrawArea area);
+    /* Click coordinates are relative to widget position */
+    virtual void on_clicked(SCoordinates p);
+    /* This version ignores position */
+    virtual void on_clicked();
+
+    virtual int GetMinimalWidth () = 0;
+    virtual int GetMinimalHeight() = 0;
     
-    virtual void draw();
-    virtual void on_clicked();
- };
+    /* A helpful macro, used by probably every drawable in its draw() func */
+    static void use_new_transform_to(int x, int y);
+};
 
 #endif //__DRAWABLE_HPP__

=== modified file 'src/label.cpp'
--- src/label.cpp	2013-07-07 08:48:44 +0000
+++ src/label.cpp	2013-07-21 13:05:30 +0000
@@ -8,11 +8,18 @@
 extern ALLEGRO_FONT* main_font;
 
 
-Label::Label(std::string _text) : Drawable(60,20), text(_text){
+Label::Label(std::string _text) : text(_text){
 
 }
 
-void Label::draw(){
+void Label::draw(SDrawArea a){
+    use_new_transform_to(a.x,a.y);
     ALLEGRO_COLOR white = al_map_rgb(255, 255, 255);
-    al_draw_text(Display::main_font, white, 30, 0 ,ALLEGRO_ALIGN_CENTRE, text.c_str());
-}
+    al_draw_text(Display::main_font, white, a.w/2, a.h/2 - 8 ,ALLEGRO_ALIGN_CENTRE, text.c_str());
+}
+
+int Label::GetMinimalHeight() {return 20;}
+int Label::GetMinimalWidth () {
+    return al_get_text_width(Display::main_font, text.c_str()) + 6; // 3px margin from both sides
+}
+

=== modified file 'src/label.hpp'
--- src/label.hpp	2013-07-07 08:48:44 +0000
+++ src/label.hpp	2013-07-21 13:05:30 +0000
@@ -6,5 +6,8 @@
     Label(std::string);
     std::string text;
     
-    virtual void draw();
+    virtual void draw(SDrawArea a) override;
+    
+    virtual int GetMinimalHeight() override;
+    virtual int GetMinimalWidth () override;
 };

=== modified file 'src/main.cpp'
--- src/main.cpp	2013-07-07 08:48:44 +0000
+++ src/main.cpp	2013-07-21 13:05:30 +0000
@@ -1,13 +1,14 @@
 #include "display.hpp"
 #include "button.hpp"
 #include "label.hpp"
-#include "view.hpp"
+#include "Fixed.hpp"
+#include "VBox.hpp"
 #include <iostream>
 #include <cstdlib>
 
-View* main_menu;
-View* additional_menu;
+Fixed additional_menu;
 
+VBox main_menu_vbox;
 
 
 void click_reaction1(){
@@ -27,10 +28,10 @@
 }
 
 void switch_to_main_menu(){
-    Display::set_view(main_menu);
+    Display::SetMainWidget(main_menu_vbox);
 }
 void switch_to_additional_menu(){
-    Display::set_view(additional_menu);
+    Display::SetMainWidget(additional_menu);
 }
 
 
@@ -38,11 +39,9 @@
 int main(){
     Display::init();
     
-    main_menu = new View();
-    additional_menu = new View();
-    
     Label label_main_menu("Main menu");
     
+    
     Button button1("Button1");
     button1.set_click_reaction(click_reaction1);
     Button button2("Button2");
@@ -61,22 +60,23 @@
     button_to_main.set_click_reaction(switch_to_main_menu);
     
     
-    main_menu->add_item(&label_main_menu,Coordinates(40,25));
-    main_menu->add_item(&button1,Coordinates(40,50));
-    main_menu->add_item(&button2,Coordinates(40,75));
-    main_menu->add_item(&button_to_2,Coordinates(40,100));
-    main_menu->add_item(&button_quit,Coordinates(40,125));
-    additional_menu->add_item(&label_additional_menu,Coordinates(42,27));
-    additional_menu->add_item(&button3,Coordinates(42,52));
-    additional_menu->add_item(&button_to_main,Coordinates(42,77));
+    main_menu_vbox.SetSpacing(3); // gaps between buttons
+    main_menu_vbox.SetMargin(5); // empty frame around the box
+    main_menu_vbox.Add(label_main_menu, 0);
+    main_menu_vbox.Add(button1,         1);
+    main_menu_vbox.Add(button2,         2);
+    main_menu_vbox.Add(button_to_2,     3, BOX_EXPAND);
+    main_menu_vbox.Add(button_quit,     4);
+    additional_menu.add_item(label_additional_menu,SCoordinates(42,27));
+    additional_menu.add_item(button3,              SCoordinates(42,52));
+    additional_menu.add_item(button_to_main,       SCoordinates(42,77));
     
-    Display::set_view(main_menu);
+    Display::SetMainWidget(main_menu_vbox);
     
     Display::main_loop();
     
     Display::cleanup();
     
-    delete main_menu, additional_menu;
     
     return 0;
 }


Follow ups