Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma warning(disable: 4018 4996)
- #include <nana/gui/wvl.hpp>
- #include <nana/gui/widgets/panel.hpp>
- #include <nana/gui/widgets/button.hpp>
- #include <nana/gui/widgets/label.hpp>
- #include <nana/gui/widgets/textbox.hpp>
- #include <nana/gui/widgets/menu.hpp>
- #if defined(NANA_WINDOWS)
- #include <nana/detail/win32/platform_spec.hpp>
- #include <windows.h>
- // #elif defined(NANA_X11)
- // #include <nana/detail/linux_X11/platform_spec.hpp>
- #else
- #endif
- #include <nana/paint/text_renderer.hpp>
- #include <nana/gui/detail/basic_window.hpp>
- #include <nana/gui/place.hpp>
- using namespace nana::gui;
- typedef widget& widget_reference;
- #include <iostream>
- #include <functional>
- #include <unordered_map>
- #include <sstream>
- #include <numeric>
- #include <memory>
- using namespace std;
- using namespace std::placeholders;
- template<typename T>
- T str_to(const std::string& str) {
- T t;
- std::stringstream ss(str);
- ss >> t;
- return t;
- }
- template <class T>
- std::string to_str(T value) {
- std::stringstream ss;
- ss << value;
- return ss.str();
- }
- template <class T>
- struct singleton {
- static inline T& inst() {
- static T instance;
- return instance;
- }
- };
- struct widget_mgr : singleton<widget_mgr> { // keep tracking of widget and its children
- typedef widget* child_t;
- typedef widget* owner_t;
- typedef vector<child_t> children_t;
- map<owner_t, children_t> children_map;
- map<child_t, owner_t> owner_map;
- static int id() {
- static int _id = 0;
- return _id++;
- }
- children_t& children(owner_t owner) { // get the children
- return children_map[owner];
- }
- owner_t owner(child_t w) { // get the owner
- return owner_map[w];
- }
- void register_(owner_t owner, child_t ch) {
- children_map[owner].push_back(ch);
- owner_map[ch] = owner;
- }
- void unregister(widget* w) {
- auto ch = children_map.find(w);
- if(ch != children_map.end()) { // remove it from children_map
- children_map.erase(ch);
- }
- auto owner = owner_map.find(w);
- if(owner != owner_map.end()) {
- auto& children = children_map[owner->second]; // remove it from its owner's children
- children.erase(std::find(children.begin(), children.end(), w));
- owner_map.erase(owner); // remove it from owner_map
- }
- }
- // apply 'callback' to the 'root' and its children recursively
- void cascade(widget* root, function<void(widget*)> callback) {
- callback(root);
- children_t& ch = children_map[root];
- for_each(ch.begin(), ch.end(), bind(&widget_mgr::cascade, this, _1, callback));
- }
- };
- struct layout_mgr : singleton<layout_mgr> {// keep tracking of created 'place layout'
- vector<place*> v_place;
- place* new_(widget* owner) {
- place* p = new place(*owner);
- register_(p);
- return p;
- }
- void register_(place* p) {
- v_place.push_back(p);
- }
- void clear() {
- v_place.clear();
- }
- };
- typedef map<string, string> property_map;
- struct property_form : public panel<true> { // the left side property widget
- typedef property_form self_t;
- typedef shared_ptr<widget> widget_ptr;
- typedef pair<widget_ptr, widget_ptr> widget_pair;
- shared_ptr<place> plc;
- shared_ptr<label> tip;
- unordered_map<string, widget_pair> widgets;
- function<void(property_map&)> committor;
- property_form(window wd, const nana::rectangle& rc = nana::rectangle())
- : panel(wd, rc)
- {
- background(0xffffff);
- plc.reset(new place(*this));
- tip.reset(new label(*this));
- tip->transparent(true);
- tip->format(true);
- }
- void append(const string& prop_name, const string& tip_str = "") {
- label* lbl = new label(*this);
- lbl->transparent(true);
- lbl->text_align(nana::align::center, nana::align_v::center);
- lbl->caption(nana::charset(prop_name));
- textbox* tbx = new textbox(*this);
- tbx->multi_lines(false);
- tbx->make_event<events::key_char>(bind(&self_t::on_char_event, this, _1));
- tbx->make_event<events::focus>(bind(&self_t::on_focus, this, tip_str));
- widgets[prop_name] = widget_pair(widget_ptr(lbl), widget_ptr(tbx));
- }
- void collocate() {
- // prepare the div string
- {
- int i = 0;
- stringstream ss;
- ss << "<vertical margin=[5,2] gap=2 ";
- for_each(widgets.begin(),
- widgets.end(),
- [&](const pair<string, widget_pair>& p)
- {
- char bf[128];
- sprintf(bf, "<weight=26 <label%d weight=60> <edit%d>>", i, i);
- ss << bf;
- i++;
- });
- ss << "<margin=5 tip>>";
- plc->div(ss.str().c_str());
- }
- // fill fields with label-edit-pair
- {
- int i = 0;
- for_each(widgets.begin(),
- widgets.end(),
- [&](const pair<string, widget_pair>& p)
- {
- stringstream ss_lbl;
- ss_lbl << "label" << i;
- stringstream ss_edt;
- ss_edt << "edit" << i;
- plc->field(ss_lbl.str().c_str()) << *p.second.first;
- plc->field(ss_edt.str().c_str()) << *p.second.second;
- i++;
- });
- }
- // fill tip field
- {
- plc->field("tip") << *tip;
- }
- plc->collocate();
- }
- void on_char_event(const eventinfo& e) {
- if(e.keyboard.key == nana::gui::keyboard::enter) {
- if(committor) {
- property_map pmap = get();
- committor(pmap);
- }
- }
- }
- void on_focus(const string& tip_str) {
- tip->caption(nana::charset(tip_str));
- }
- // apply 'callback' to all properties
- void walk_through(const function<void(pair<string, widget_pair>)>& callback) {
- for_each(widgets.begin(), widgets.end(), callback);
- }
- void clear() {
- walk_through([](pair<string, widget_pair>& pr) {
- pr.second.second.get()->caption(L"");
- });
- }
- void set(const property_map& pmap) {
- clear();
- walk_through([&](pair<string, widget_pair>& pr) {
- string name = pr.first;
- if(pmap.find(name) != pmap.end() && pmap.at(name).length() > 0) {
- pr.second.second->caption(nana::charset(pmap.at(name)));
- }
- });
- }
- property_map get() {
- property_map pmap;
- walk_through([&](pair<string, widget_pair>& pr) {
- string name = pr.first,
- text = nana::charset(pr.second.second->caption());
- if(text.length() > 0) {
- pmap[name] = text;
- }
- });
- return pmap;
- }
- void set_committor(function<void(property_map&)> cmt) {
- committor = cmt;
- }
- };
- namespace util {
- #define RESIZE_RADIUS 5
- bool is_tl(const nana::rectangle& rc, const nana::point& p) {
- return p.x <= RESIZE_RADIUS && p.y <= RESIZE_RADIUS;
- }
- bool is_top(const nana::rectangle& rc, const nana::point& p) {
- return p.x > RESIZE_RADIUS && p.x < (rc.width - RESIZE_RADIUS) && p.y <= RESIZE_RADIUS;
- }
- bool is_tr(const nana::rectangle& rc, const nana::point& p) {
- return p.x >= (rc.width - RESIZE_RADIUS) && p.y <= RESIZE_RADIUS;
- }
- bool is_left(const nana::rectangle& rc, const nana::point& p) {
- return p.x <= RESIZE_RADIUS && p.y > RESIZE_RADIUS && p.y < (rc.height - RESIZE_RADIUS);
- }
- bool is_right(const nana::rectangle& rc, const nana::point& p) {
- return p.x >= (rc.width - RESIZE_RADIUS) && p.y > RESIZE_RADIUS && p.y < (rc.height - RESIZE_RADIUS);
- }
- bool is_bl(const nana::rectangle& rc, const nana::point& p) {
- return p.x <= RESIZE_RADIUS && p.y >= (rc.height - RESIZE_RADIUS);
- }
- bool is_bottom(const nana::rectangle& rc, const nana::point& p) {
- return p.x > RESIZE_RADIUS && p.x < (rc.width - RESIZE_RADIUS) && p.y >= (rc.height - RESIZE_RADIUS);
- }
- bool is_br(const nana::rectangle& rc, const nana::point& p) {
- return p.x >= (rc.width - RESIZE_RADIUS) && p.y >= (rc.height - RESIZE_RADIUS);
- }
- // near the border of widget
- bool is_in_resize_rect(const nana::rectangle& rc, const nana::point& p) {
- return p.x <= RESIZE_RADIUS || p.x >= (rc.width-RESIZE_RADIUS)
- || p.y <= RESIZE_RADIUS || p.y >= (rc.height-RESIZE_RADIUS);
- }
- }
- struct mouse_event_handler { // base class for 'dragger' and 'resizer'
- typedef mouse_event_handler self_t;
- widget* wd_ptr;
- void bind(widget_reference widget) {
- using namespace std::placeholders;
- wd_ptr = &widget;
- wd_ptr->make_event<events::mouse_down>(std::bind(&self_t::mouse_down, this, _1));
- wd_ptr->make_event<events::mouse_up>(std::bind(&self_t::mouse_up, this, _1));
- wd_ptr->make_event<events::mouse_move>(std::bind(&self_t::mouse_move, this, _1));
- }
- virtual void mouse_down(const eventinfo&) = 0;
- virtual void mouse_up(const eventinfo&) = 0;
- virtual void mouse_move(const eventinfo&) = 0;
- };
- struct dragger : mouse_event_handler {
- bool is_dragging;
- nana::point start_cursor_pos;
- nana::point start_wd_pos;
- dragger() : is_dragging(false) {}
- void mouse_down(const eventinfo& e) {
- int x = e.mouse.x,
- y = e.mouse.y;
- nana::rectangle rc(wd_ptr->size());
- // dragging, not resizing
- if(x > RESIZE_RADIUS && x < rc.width-RESIZE_RADIUS
- && y > RESIZE_RADIUS && y < rc.height-RESIZE_RADIUS)
- {
- // start dragging
- start_cursor_pos = API::cursor_position();
- start_wd_pos = wd_ptr->pos();
- API::capture_window(*wd_ptr, true);
- is_dragging = true;
- }
- }
- void mouse_up(const eventinfo& e) {
- if(is_dragging) {
- nana::rectangle rc(wd_ptr->size());
- API::capture_window(*wd_ptr, false);
- is_dragging = false;
- }
- }
- void mouse_move(const eventinfo& e) {
- if(is_dragging) {
- nana::point ccp = API::cursor_position();
- auto diff_x = ccp.x - start_cursor_pos.x,
- diff_y = ccp.y - start_cursor_pos.y;
- wd_ptr->move(start_wd_pos.x + diff_x, start_wd_pos.y + diff_y);
- }
- }
- };
- struct resizer : mouse_event_handler {
- bool is_resizing;
- nana::point start_cursor_pos;
- nana::point start_wd_pos;
- nana::size start_size_wd;
- enum resize_direction {
- tl, top, tr,
- left, none, right,
- bl, bottom, br
- } dir;
- resizer() : is_resizing(false) {}
- void mouse_down(const eventinfo& e) {
- using namespace util;
- nana::rectangle rc(wd_ptr->size());
- nana::point pt(e.mouse.x, e.mouse.y);
- if(is_in_resize_rect(rc, pt)) {
- dir = is_tl(rc, pt) ? tl
- : is_top(rc, pt) ? top
- : is_tr(rc, pt) ? tr
- : is_left(rc, pt) ? left
- : is_right(rc, pt) ? right
- : is_bl(rc, pt) ? bl
- : is_bottom(rc, pt) ? bottom
- : is_br(rc, pt) ? br : none;
- start_cursor_pos = API::cursor_position();
- start_wd_pos = wd_ptr->pos();
- start_size_wd = wd_ptr->size();
- API::capture_window(*wd_ptr, true);
- is_resizing = true;
- }
- }
- void mouse_up(const eventinfo& e) {
- if(is_resizing) {
- API::capture_window(*wd_ptr, false);
- is_resizing = false;
- }
- }
- void mouse_move(const eventinfo& e) {
- if(is_resizing) {
- nana::point cp = API::cursor_position();
- int diff_x = cp.x - start_cursor_pos.x,
- diff_y = cp.y - start_cursor_pos.y;
- int x = start_wd_pos.x,
- y = start_wd_pos.y,
- w = start_size_wd.width,
- h = start_size_wd.height;
- if(dir == tl) {
- x += diff_x; y += diff_y;
- w -= diff_x; h -= diff_y;
- } else if(dir == top) {
- y += diff_y; h -= diff_y;
- } else if(dir == tr) {
- y += diff_y;
- w += diff_x; h -= diff_y;
- } else if(dir == left) {
- x += diff_x;
- w -= diff_x;
- } else if(dir == right) {
- w += diff_x;
- } else if(dir == bl) {
- x += diff_x;
- w -= diff_x; h += diff_y;
- } else if(dir == bottom) {
- h += diff_y;
- } else if(dir == br) {
- w += diff_x;h += diff_y;
- }
- wd_ptr->move(x, y);
- wd_ptr->size(w, h);
- }
- }
- };
- struct resizer_drawer { // the drawer_trigger for resizer
- typedef resizer_drawer self_t;
- typedef nana::paint::graphics& graph_reference;
- widget* wd_ptr;
- nana::gui::cursor cursor_shape;
- resizer_drawer() {
- cursor_shape = cursor::arrow;
- }
- void bind(widget_reference widget) {
- wd_ptr = &widget;
- }
- void mouse_move(graph_reference graph, const eventinfo& e) {
- using namespace util;
- if(wd_ptr->focused()) {
- nana::rectangle rc(graph.size());
- nana::point pt(e.mouse.x, e.mouse.y);
- if(is_tl(rc, pt) || is_br(rc, pt)) {
- cursor_shape = cursor::size_top_left;
- } else if(is_tr(rc, pt) || is_bl(rc, pt)) {
- cursor_shape = cursor::size_bottom_left;
- } else if(is_left(rc, pt) || is_right(rc, pt)) {
- cursor_shape = cursor::size_we;
- } else if(is_top(rc, pt) || is_bottom(rc, pt)) {
- cursor_shape = cursor::size_ns;
- } else {
- cursor_shape = cursor::arrow;
- }
- } else {
- cursor_shape = cursor::arrow;
- }
- update_mouse_shape();
- }
- void update_mouse_shape() {
- wd_ptr->cursor(cursor_shape);
- }
- void draw(graph_reference graph) {
- if(wd_ptr->focused() && !graph.empty()) {
- draw_dash_line(graph);
- draw_8_dots(graph);
- }
- update_mouse_shape();
- }
- void draw_dash_line(graph_reference graph) {
- window wd = wd_ptr->handle();
- nana::rectangle rc(graph.size());
- #if defined(NANA_WINDOWS)
- HDC hdc = graph.handle()->context;
- RECT r = {rc.x, rc.y, rc.right(), rc.bottom()};
- DrawFocusRect(hdc, &r);
- #else
- graph.rectangle(rc, 0xff, false);
- #endif
- }
- void draw_8_dots(graph_reference graph) {
- nana::rectangle rc(graph.size());
- #define CLR 0xff // color blue
- #define W 5 // width
- graph.rectangle(rc.x, rc.y, W, W, CLR, false); // top left
- graph.rectangle((rc.width-W)/2, rc.y, W, W, CLR, false); // top center
- graph.rectangle(rc.width-W, rc.y, W, W, CLR, false); // top right
- graph.rectangle(0, (rc.height-W)/2, W, W, CLR, false); // left center
- graph.rectangle(rc.width-W, (rc.height-W)/2, W, W, CLR, false); // right center
- graph.rectangle(rc.x, rc.height-W, W, W, CLR, false); // bottom left
- graph.rectangle((rc.width-W)/2, rc.height-W, W, W, CLR, false); // bottom center
- graph.rectangle(rc.width-W, rc.height-W, W, W, CLR, false); // bottom right
- }
- };
- // base class for 'div_panel' and 'my_widget' which provides 'property' functionality
- struct my_widget_base {
- enum type_t {
- wdgt, div
- };
- property_map prop;
- virtual void apply_property(property_map& pmap) {
- widget* w = dynamic_cast<widget*>(this);
- w->caption(nana::charset(pmap["name"]));
- w->move(str_to<int>(pmap["x"]), str_to<int>(pmap["y"]));
- w->size(str_to<int>(pmap["width"]), str_to<int>(pmap["height"]));
- this->prop = pmap;
- }
- #define DIV_BEG "<"
- #define DIV_END ">"
- std::string to_div_str_beg(bool self_property, bool children_property) {
- stringstream ss;
- widget* w = dynamic_cast<widget*>(this);
- ss << DIV_BEG;
- if(self_property) { // attributes for aligning itself in its parent
- ss << " " << (string)nana::charset(w->caption());
- if(prop.find("weight") != prop.end())
- ss << " weight=" << prop.at("weight");
- }
- if(children_property) { // attributes for aligning its children
- if(prop.find("align") != prop.end())
- ss << " " << prop.at("align");
- if(prop.find("gap") != prop.end())
- ss << " gap=" << prop.at("gap");
- if(prop.find("margin") != prop.end())
- ss << " margin=" << prop.at("margin");
- if(prop.find("grid") != prop.end())
- ss << " grid=" << prop.at("grid");
- }
- return ss.str();
- }
- std::string to_div_str_end() {
- return DIV_END;
- }
- std::string children_div_str(bool recursive, bool self_property, bool children_property) {
- vector<widget*>& ch = widget_mgr::inst().children(dynamic_cast<widget*>(this));
- stringstream ss;
- for_each(ch.begin(), ch.end(), [&](widget* c) {
- my_widget_base* wb = dynamic_cast<my_widget_base*>(c);
- ss << " " << wb->to_div_str_beg(self_property, children_property);
- if(recursive)
- ss << wb->children_div_str(recursive, self_property, children_property);
- ss << wb->to_div_str_end();
- });
- return ss.str();
- }
- void do_layout() {
- widget* _this = dynamic_cast<widget*>(this);
- vector<widget*>& children = widget_mgr::inst().children(_this);
- if(children.size() == 0)
- return;
- place* plc = layout_mgr::inst().new_(_this);
- string div_str = to_div_str_beg(false, true)
- + children_div_str(false, true, false)
- + to_div_str_end();
- plc->div(div_str.c_str());
- cout << "apply_div for <" << (string)nana::charset(_this->caption())
- << ">: " << div_str << endl;
- // fill fields
- for_each(children.begin(), children.end(), [&](widget* wgt) {
- string name = (string)nana::charset(wgt->caption());
- plc->field(name.c_str()) << *wgt;
- });
- plc->collocate();
- }
- virtual type_t type() = 0;
- };
- template <typename super_t>
- struct my_widget_trigger: public super_t {
- widget* wd_ptr;
- typedef nana::paint::graphics& graph_reference;
- resizer_drawer rsz;
- struct attr_tag {
- bool focused;
- } attr_;
- my_widget_trigger() : super_t() {
- attr_.focused = false;
- }
- void attached(widget_reference widget, graph_reference graph) {
- wd_ptr = &widget;
- window wd = widget.handle();
- rsz.bind(widget);
- using namespace API::dev;
- make_drawer_event<events::key_down>(wd);
- make_drawer_event<events::focus>(wd);
- make_drawer_event<events::mouse_move>(wd);
- }
- void refresh(graph_reference graph) {
- if(!graph.empty()) {
- window wd = wd_ptr->handle();
- draw_background(graph);
- draw_text(graph);
- rsz.draw(graph);
- API::lazy_refresh();
- }
- }
- virtual void draw_background(graph_reference graph) {
- nana::rectangle r(graph.size());
- if(attr_.focused) {
- r.pare_off(1); // for the dash line
- }
- nana::color_t color_start = nana::paint::graphics::mix(0x0000cc, 0xFFFFFF, 0.2);
- nana::color_t color_end = nana::paint::graphics::mix(0x0000dc, 0x0, 0.95);
- graph.shadow_rectangle(r, color_start, color_end, true);
- }
- virtual void draw_text(graph_reference graph) {// code from button.cpp
- nana::string text = wd_ptr->caption();
- nana::size ts = graph.text_extent_size(text);
- int x = (graph.width() - ts.width) >> 1;
- int y = (graph.height() - ts.height) >> 1;
- if(ts.width) {
- #define fgcolor 0xFF
- graph.string(x, y, fgcolor, text);
- }
- }
- // handle UP/DOWN/LEFT/RIGHT Key
- void key_down(graph_reference graph, const eventinfo& e) {
- #define STEP 1
- auto pt = wd_ptr->pos();
- switch(e.keyboard.key) {
- case keyboard::os_arrow_up:
- wd_ptr->move(pt.x, pt.y - STEP);
- break;
- case keyboard::os_arrow_down:
- wd_ptr->move(pt.x, pt.y + STEP);
- break;
- case keyboard::os_arrow_left:
- wd_ptr->move(pt.x - STEP, pt.y);
- break;
- case keyboard::os_arrow_right:
- wd_ptr->move(pt.x + STEP, pt.y);
- break;
- }
- }
- void focus(graph_reference graph, const eventinfo& e) {
- attr_.focused = e.focus.getting;
- refresh(graph);
- }
- void mouse_move(graph_reference graph, const eventinfo& e) {
- rsz.mouse_move(graph, e);
- }
- };
- struct my_widget
- : my_widget_base
- , public widget_object<category::widget_tag, my_widget_trigger<drawer_trigger> >
- {
- resizer rsz;
- dragger dg;
- my_widget(widget& w, const nana::rectangle& rc = nana::rectangle(), const nana::string& text = L"") {
- create(w, rc);
- caption(text);
- dg.bind(*this);
- rsz.bind(*this);
- }
- my_widget_base::type_t type() { return my_widget_base::wdgt; }
- };
- class div_panel_trigger : public my_widget_trigger<drawer_trigger> {
- void draw_background(graph_reference graph) {
- nana::rectangle r(graph.size());
- if(attr_.focused) {
- r.pare_off(1); // for the dash line
- }
- nana::color_t color_start = nana::paint::graphics::mix(0xaacccc, 0xFFFFFF, 0.2);
- nana::color_t color_end = nana::paint::graphics::mix(0xbbdddd, 0x0, 0.95);
- graph.shadow_rectangle(r, color_start, color_end, true);
- }
- virtual void draw_text(graph_reference graph) {
- // hide the name for div_panel
- }
- };
- struct div_panel
- : my_widget_base
- , public widget_object<category::widget_tag, div_panel_trigger >
- {
- typedef div_panel self_t;
- resizer rsz;
- dragger dg;
- div_panel(widget& w, const nana::rectangle& rc = nana::rectangle(), const nana::string& text = L"") {
- create(w, rc);
- caption(text);
- dg.bind(*this);
- rsz.bind(*this);
- }
- my_widget_base::type_t type() { return my_widget_base::div; }
- };
- // the main class
- struct design_app : public form {
- typedef design_app self_t;
- shared_ptr<div_panel> designer; // the design area
- shared_ptr<textbox> console; // the console
- shared_ptr<property_form> prop_form; // the left side property_form
- shared_ptr<place> plc;
- shared_ptr<menu> mnu;
- nana::point menu_point; // the right clicking point, create widget there
- widget* focused_widget;
- design_app(const nana::rectangle& rc) : form(rc), focused_widget(NULL)
- {
- background(0xffffff);
- mnu.reset(new menu);
- mnu->append(L"new div", bind(&self_t::on_new_div_click, this, placeholders::_1));
- mnu->append(L"new element", bind(&self_t::on_new_widget_click, this, placeholders::_1));
- mnu->append_splitter();
- mnu->append(L"delete", bind(&self_t::on_delete_click, this, placeholders::_1));
- // designer panel
- designer.reset(new div_panel(*this, nana::rectangle(), L"designer"));
- bind_events_to_newly_created(designer.get());
- console.reset(new textbox(*this));
- console->line_wrapped(true);
- prop_form.reset(new property_form(*this));
- prop_form->set_committor(bind(&self_t::on_commit, this, placeholders::_1));
- prop_form->append("name");
- prop_form->append("x");
- prop_form->append("y");
- prop_form->append("width");
- prop_form->append("height");
- prop_form->append("weight", "eg:\nweight=200\nweight=30%");
- prop_form->append("gap", "eg:\ngap=5");
- prop_form->append("margin", "eg, margin =\n"
- "\n10 (all sides)"
- "\n[top]"
- "\n[vertcal,horizontal]"
- "\n[top,right,bottom]"
- "\n[top,right,bottom,right]"
- "\n<color=0x888888>margin can be percent:</>"
- "\n[10%,20%] or 15%"
- );
- prop_form->append("align", "can be \"vertical\"");
- prop_form->append("grid", "eg:\ngrid=[columns, rows]\n<color=0x888888>plc.room(x, columns, rows)</>\n");
- prop_form->collocate();
- plc.reset(new place(*this));
- plc->div("< <vertical margin=5 weight=180 <prop_form> > <vertical <design> <weight=150 console>> >");
- plc->field("prop_form") << *prop_form;
- plc->field("design") << *designer;
- plc->field("console") << *console;
- plc->collocate();
- }
- void set_focused_widget(widget* w) {
- focused_widget = w;
- }
- void set_menu_point(const eventinfo& e) {
- menu_point = nana::point(e.mouse.x, e.mouse.y);
- }
- void bind_events_to_newly_created(widget* widget) {
- // save the focused widget
- widget->make_event<events::focus>(std::bind(&self_t::set_focused_widget, this, widget));
- // menu
- widget->make_event<events::click>(std::bind(&self_t::set_menu_point, this, placeholders::_1));
- widget->make_event<events::click>(menu_popuper(*mnu));
- // display properties on the left panel
- widget->make_event<events::click>(std::bind(&self_t::display_property, this, widget)); // for click/dragging
- widget->make_event<events::focus>(std::bind(&self_t::display_property, this, widget)); // for manually call widget->focus()
- }
- void display_property(widget* w) {
- property_map pmap = dynamic_cast<my_widget_base*>(w)->prop;
- pmap["x"] = to_str(w->pos().x);
- pmap["y"] = to_str(w->pos().y);
- pmap["width"] = to_str(w->size().width);
- pmap["height"] = to_str(w->size().height);
- pmap["name"] = nana::charset(w->caption());
- prop_form->set(pmap);
- }
- void on_commit(property_map& pmap) {
- // save the modified property to widget*
- my_widget_base* w = dynamic_cast<my_widget_base*>(focused_widget);
- if(focused_widget) {
- w->apply_property(pmap);
- }
- // display the div str in console
- string div_str = designer->to_div_str_beg(true, true)
- + designer->children_div_str(true, true, true)
- + designer->to_div_str_end();
- console->caption(nana::charset(div_str));
- try {
- do_layout();
- } catch(const runtime_error& e) {
- console->caption(nana::charset(e.what()));
- }
- }
- void do_layout() {
- layout_mgr::inst().clear(); // delete all the previous places
- widget_mgr::inst().cascade(designer.get(), [](widget* w) {
- my_widget_base* wb = dynamic_cast<my_widget_base*>(w);
- wb->do_layout();
- });
- }
- void on_new_div_click(const menu::item_proxy& ip) { // create a new div
- nana::string div_name = nana::charset(string("div_") + to_str(widget_mgr::id()));
- widget* w = new div_panel(*focused_widget, nana::rectangle(menu_point, nana::size(100, 40)), div_name);
- bind_events_to_newly_created(w);
- widget_mgr::inst().register_(focused_widget, w);
- w->focus();
- }
- void on_new_widget_click(const menu::item_proxy& ip) { // create a new widget
- nana::string widget_name = nana::charset(string("widget_") + to_str(widget_mgr::id());
- widget* w = new my_widget(*focused_widget, nana::rectangle(menu_point, nana::size(100, 40)), widget_name);
- bind_events_to_newly_created(w);
- widget_mgr::inst().register_(focused_widget, w);
- w->focus();
- }
- void on_delete_click(const menu::item_proxy& ip) { // delete a div/widget
- if(focused_widget == designer.get())
- return;
- widget_mgr::inst().unregister(focused_widget);
- delete focused_widget;
- focused_widget = NULL;
- }
- };
- int main() {
- design_app app(API::make_center(600, 480));
- app.show();
- exec();
- }
Advertisement
Add Comment
Please, Sign In to add comment