Skip to content

Commit

Permalink
GUI2/Tree View: added interface for moving nodes between parent nodes
Browse files Browse the repository at this point in the history
(cherry-picked from commit fa7c967)
  • Loading branch information
Vultraz committed Oct 7, 2018
1 parent 97e05ca commit 766a0ff
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/gui/dialogs/multiplayer/mp_options_helper.cpp
Expand Up @@ -129,7 +129,7 @@ int mp_options_helper::remove_nodes_for_type(const std::string& type)

// Remove each node in reverse, so that in the end we have the position of the first node removed
for(auto i = type_node_vector.rbegin(); i != type_node_vector.rend(); i++) {
position = options_tree_.remove_node(*i);
position = options_tree_.remove_node(*i).second;
}

type_node_vector.clear();
Expand Down
10 changes: 6 additions & 4 deletions src/gui/widgets/tree_view.cpp
Expand Up @@ -20,7 +20,6 @@
#include "gui/core/window_builder/helper.hpp"
#include "gui/core/register_widget.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/tree_view_node.hpp"
#include "gui/widgets/window.hpp"
#include "gettext.hpp"
#include "wml_exception.hpp"
Expand Down Expand Up @@ -67,19 +66,22 @@ tree_view_node& tree_view::add_node(
return get_root_node().add_child(id, data, index);
}

int tree_view::remove_node(tree_view_node* node)
std::pair<tree_view_node::ptr_t, int> tree_view::remove_node(tree_view_node* node)
{
assert(node && node != root_node_ && node->parent_node_);
const point node_size = node->get_size();

tree_view_node::node_children_vector& siblings = node->parent_node_->children_;

auto node_itor = std::find_if(siblings.begin(), siblings.end(),
[node](const std::unique_ptr<tree_view_node>& c) { return c.get() == node; }
[node](const tree_view_node::ptr_t& c) { return c.get() == node; }
);

assert(node_itor != siblings.end());

auto old_node = std::move(*node_itor);
old_node->parent_node_ = nullptr;

const int position = std::distance(siblings.begin(), node_itor);

siblings.erase(node_itor);
Expand All @@ -89,7 +91,7 @@ int tree_view::remove_node(tree_view_node* node)
resize_content(0, -node_size.y);
}

return position;
return std::make_pair(std::move(old_node), position);
}

void tree_view::clear()
Expand Down
11 changes: 10 additions & 1 deletion src/gui/widgets/tree_view.hpp
Expand Up @@ -15,6 +15,7 @@
#pragma once

#include "gui/widgets/scrollbar_container.hpp"
#include "gui/widgets/tree_view_node.hpp"

namespace gui2
{
Expand Down Expand Up @@ -59,7 +60,15 @@ class tree_view : public scrollbar_container
const std::map<std::string /* widget id */, string_map>& data,
const int index = -1);

int remove_node(tree_view_node* tree_view_node);
/**
* Removes the given node as a child of its parent node.
*
* @param node A pointer to the node to remove.
*
* @returns A pair consisting of a smart pointer managing the removed
* node, and its position before removal.
*/
std::pair<tree_view_node::ptr_t, int> remove_node(tree_view_node* node);

void clear();

Expand Down
27 changes: 16 additions & 11 deletions src/gui/widgets/tree_view_node.cpp
Expand Up @@ -127,33 +127,38 @@ void tree_view_node::clear_before_destruct()
}
}

tree_view_node& tree_view_node::add_child(
const std::string& id,
const std::map<std::string /* widget id */, string_map>& data,
const int index)
tree_view_node& tree_view_node::add_child_impl(ptr_t&& new_node, const int index)
{
auto itor = children_.end();

if(static_cast<std::size_t>(index) < children_.size()) {
itor = children_.begin() + index;
}

itor = children_.emplace(itor, new tree_view_node(id, this, get_tree_view(), data));
tree_view_node& node = **children_.insert(itor, std::move(new_node));

// NOTE: we currently don't support moving nodes between different trees, so this
// just ensures that wasn't tried. Remove this if we implement support for that.
assert(node.tree_view_ == tree_view_);

// Safety check. Might only fail if someone accidentally removed the parent_node_
// setter in add_child().
assert(node.parent_node_ == this);

if(is_folded() /*|| is_root_node()*/) {
return **itor;
return node;
}

if(get_tree_view().get_size() == point()) {
return **itor;
return node;
}

assert(get_tree_view().content_grid());
const point current_size = get_tree_view().content_grid()->get_size();

// Calculate width modification.
// This increases tree width if the width of the new node is greater than the current width.
point best_size = (*itor)->get_best_size();
point best_size = node.get_best_size();
best_size.x += get_indentation_level() * get_tree_view().indentation_step_size_;

const int width_modification = best_size.x > current_size.x
Expand All @@ -165,7 +170,7 @@ tree_view_node& tree_view_node::add_child(
// is larger than its current size. This prevents the scrollbar being reserved even when there's obviously
// enough visual space.

// Throw away cached best size to force a recomputation.
// Throw away cached best size to force a recalculation.
get_tree_view().layout_initialize(false);

const point tree_best_size = get_tree_view().get_best_size();
Expand All @@ -177,9 +182,9 @@ tree_view_node& tree_view_node::add_child(
assert(height_modification >= 0);

// Request new size.
get_tree_view().resize_content(width_modification, height_modification, -1, (*itor)->calculate_ypos());
get_tree_view().resize_content(width_modification, height_modification, -1, node.calculate_ypos());

return **itor;
return node;
}

unsigned tree_view_node::get_indentation_level() const
Expand Down
34 changes: 29 additions & 5 deletions src/gui/widgets/tree_view_node.hpp
Expand Up @@ -50,7 +50,7 @@ class tree_view_node : public widget
~tree_view_node();

/**
* Adds a child item to the list of child nodes.
* Constructs a new child node.
*
* @param id The id of the node definition to use for the
* new node.
Expand All @@ -64,10 +64,26 @@ class tree_view_node : public widget
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
*/
tree_view_node&
add_child(const std::string& id,
const std::map<std::string /* widget id */, string_map>& data,
const int index = -1);
tree_view_node& add_child(const std::string& id,
const std::map<std::string /* widget id */, string_map>& data,
const int index = -1)
{
ptr_t new_node(new tree_view_node(id, this, get_tree_view(), data));
return add_child_impl(std::move(new_node), index);
}

/**
* Adds a previously-constructed node as a child of this node at the given position.
*
* @param new_node A smart pointer to the node object to insert.
* @param index The item before which to add the new item,
* 0 == begin, -1 == end.
*/
tree_view_node& add_child(ptr_t new_node, const int index = -1)
{
new_node->parent_node_ = this;
return add_child_impl(std::move(new_node), index);
}

/**
* Adds a sibbling for a node at the end of the list.
Expand All @@ -90,12 +106,20 @@ class tree_view_node : public widget
return parent_node().add_child(id, data);
}

private:
/** Implementation detail for @ref add_child. */
tree_view_node& add_child_impl(ptr_t&& new_node, const int index);

public:
/**
* Is this node the root node?
*
* When the parent tree view is created it adds one special node, the root
* node. This node has no parent node and some other special features so
* several code paths need to check whether they are the parent node.
*
* This also returns true for a detecthed node returned with @ref tree_view::
* remove_node.
*/
bool is_root_node() const
{
Expand Down

0 comments on commit 766a0ff

Please sign in to comment.