aboutsummaryrefslogtreecommitdiff
path: root/gdb/tui
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2020-02-22 11:48:26 -0700
committerTom Tromey <tom@tromey.com>2020-02-22 11:48:33 -0700
commit7c043ba695a3cee067554b1e871e60f7934512b4 (patch)
tree6943c911cf3ad9ad274ead117e0dd60a2de89858 /gdb/tui
parent6bc5664858d6869513b9b98861c813675231e5b5 (diff)
downloadgdb-7c043ba695a3cee067554b1e871e60f7934512b4.zip
gdb-7c043ba695a3cee067554b1e871e60f7934512b4.tar.gz
gdb-7c043ba695a3cee067554b1e871e60f7934512b4.tar.bz2
Add horizontal splitting to TUI layout
This changes the TUI layout engine to add horizontal splitting. Now, windows can be side-by-side. A horizontal split is defined using the "-horizontal" parameter to "tui new-layout". This also adds the first "winheight" test to the test suite. One open question is whether we want a new "winwidth" command, now that horizontal layouts are possible. This is easily done using the generic layout code. gdb/ChangeLog 2020-02-22 Tom Tromey <tom@tromey.com> PR tui/17850: * tui/tui-win.c (tui_gen_win_info::max_width): New method. * tui/tui-layout.h (class tui_layout_base) <get_sizes>: Add "height" argument. (class tui_layout_window) <get_sizes>: Likewise. (class tui_layout_split) <tui_layout_split>: Add "vertical" argument. <get_sizes>: Add "height" argument. <m_vertical>: New field. * tui/tui-layout.c (tui_layout_split::clone): Update. (tui_layout_split::get_sizes): Add "height" argument. (tui_layout_split::adjust_size, tui_layout_split::apply): Update. (tui_new_layout_command): Parse "-horizontal". (_initialize_tui_layout): Update help string. (tui_layout_split::specification): Add "-horizontal" when needed. * tui/tui-layout.c (tui_layout_window::get_sizes): Add "height" argument. * tui/tui-data.h (struct tui_gen_win_info) <max_width, min_width>: New methods. gdb/doc/ChangeLog 2020-02-22 Tom Tromey <tom@tromey.com> PR tui/17850: * gdb.texinfo (TUI Commands): Document horizontal layouts. gdb/testsuite/ChangeLog 2020-02-22 Tom Tromey <tom@tromey.com> PR tui/17850: * gdb.tui/new-layout.exp: Add horizontal layout and winheight tests. Change-Id: I38b35e504f34698578af86686be03c0fefd954ae
Diffstat (limited to 'gdb/tui')
-rw-r--r--gdb/tui/tui-data.h9
-rw-r--r--gdb/tui/tui-layout.c147
-rw-r--r--gdb/tui/tui-layout.h19
-rw-r--r--gdb/tui/tui-win.c8
4 files changed, 125 insertions, 58 deletions
diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index 2badcd4..e15ac58 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -82,6 +82,15 @@ public:
/* Compute the minimum height of this window. */
virtual int min_height () const = 0;
+ /* Compute the maximum width of this window. */
+ int max_width () const;
+
+ /* Compute the minimum width of this window. */
+ int min_width () const
+ {
+ return 3;
+ }
+
/* Return true if this window can be boxed. */
virtual bool can_box () const
{
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index e1833cd..c103786 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -355,12 +355,20 @@ tui_layout_window::apply (int x_, int y_, int width_, int height_)
/* See tui-layout.h. */
void
-tui_layout_window::get_sizes (int *min_height, int *max_height)
+tui_layout_window::get_sizes (bool height, int *min_value, int *max_value)
{
if (m_window == nullptr)
m_window = tui_get_window_by_name (m_contents);
- *min_height = m_window->min_height ();
- *max_height = m_window->max_height ();
+ if (height)
+ {
+ *min_value = m_window->min_height ();
+ *max_value = m_window->max_height ();
+ }
+ else
+ {
+ *min_value = m_window->min_width ();
+ *max_value = m_window->max_width ();
+ }
}
/* See tui-layout.h. */
@@ -430,7 +438,7 @@ tui_layout_split::add_window (const char *name, int weight)
std::unique_ptr<tui_layout_base>
tui_layout_split::clone () const
{
- tui_layout_split *result = new tui_layout_split ();
+ tui_layout_split *result = new tui_layout_split (m_vertical);
for (const split &item : m_splits)
{
std::unique_ptr<tui_layout_base> next = item.layout->clone ();
@@ -443,16 +451,29 @@ tui_layout_split::clone () const
/* See tui-layout.h. */
void
-tui_layout_split::get_sizes (int *min_height, int *max_height)
+tui_layout_split::get_sizes (bool height, int *min_value, int *max_value)
{
- *min_height = 0;
- *max_height = 0;
+ *min_value = 0;
+ *max_value = 0;
+ bool first_time = true;
for (const split &item : m_splits)
{
int new_min, new_max;
- item.layout->get_sizes (&new_min, &new_max);
- *min_height += new_min;
- *max_height += new_max;
+ item.layout->get_sizes (height, &new_min, &new_max);
+ /* For the mismatch case, the first time through we want to set
+ the min and max to the computed values -- the "first_time"
+ check here is just a funny way of doing that. */
+ if (height == m_vertical || first_time)
+ {
+ *min_value += new_min;
+ *max_value += new_max;
+ }
+ else
+ {
+ *min_value = std::max (*min_value, new_min);
+ *max_value = std::min (*max_value, new_max);
+ }
+ first_time = false;
}
}
@@ -502,6 +523,8 @@ tui_layout_split::adjust_size (const char *name, int new_height)
return HANDLED;
if (adjusted == FOUND)
{
+ if (!m_vertical)
+ return FOUND;
found_index = i;
break;
}
@@ -524,7 +547,7 @@ tui_layout_split::adjust_size (const char *name, int new_height)
int index = (found_index + 1 + i) % m_splits.size ();
int new_min, new_max;
- m_splits[index].layout->get_sizes (&new_min, &new_max);
+ m_splits[index].layout->get_sizes (m_vertical, &new_min, &new_max);
if (delta < 0)
{
@@ -571,23 +594,23 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
width = width_;
height = height_;
- struct height_info
+ struct size_info
{
- int height;
- int min_height;
- int max_height;
+ int size;
+ int min_size;
+ int max_size;
/* True if this window will share a box border with the previous
window in the list. */
bool share_box;
};
- std::vector<height_info> info (m_splits.size ());
+ std::vector<size_info> info (m_splits.size ());
- /* Step 1: Find the min and max height of each sub-layout.
- Fixed-sized layouts are given their desired height, and then the
+ /* Step 1: Find the min and max size of each sub-layout.
+ Fixed-sized layouts are given their desired size, and then the
remaining space is distributed among the remaining windows
according to the weights given. */
- int available_height = height;
+ int available_size = m_vertical ? height : width;
int last_index = -1;
int total_weight = 0;
for (int i = 0; i < m_splits.size (); ++i)
@@ -597,7 +620,8 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
/* Always call get_sizes, to ensure that the window is
instantiated. This is a bit gross but less gross than adding
special cases for this in other places. */
- m_splits[i].layout->get_sizes (&info[i].min_height, &info[i].max_height);
+ m_splits[i].layout->get_sizes (m_vertical, &info[i].min_size,
+ &info[i].max_size);
if (!m_applied
&& cmd_win_already_exists
@@ -607,15 +631,17 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
/* If this layout has never been applied, then it means the
user just changed the layout. In this situation, it's
desirable to keep the size of the command window the
- same. Setting the min and max heights this way ensures
+ same. Setting the min and max sizes this way ensures
that the resizing step, below, does the right thing with
this window. */
- info[i].min_height = TUI_CMD_WIN->height;
- info[i].max_height = TUI_CMD_WIN->height;
+ info[i].min_size = (m_vertical
+ ? TUI_CMD_WIN->height
+ : TUI_CMD_WIN->width);
+ info[i].max_size = info[i].min_size;
}
- if (info[i].min_height == info[i].max_height)
- available_height -= info[i].min_height;
+ if (info[i].min_size == info[i].max_size)
+ available_size -= info[i].min_size;
else
{
last_index = i;
@@ -623,54 +649,58 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
}
/* Two adjacent boxed windows will share a border, making a bit
- more height available. */
+ more size available. */
if (i > 0
&& m_splits[i - 1].layout->bottom_boxed_p ()
&& m_splits[i].layout->top_boxed_p ())
info[i].share_box = true;
}
- /* Step 2: Compute the height of each sub-layout. Fixed-sized items
+ /* Step 2: Compute the size of each sub-layout. Fixed-sized items
are given their fixed size, while others are resized according to
their weight. */
- int used_height = 0;
+ int used_size = 0;
for (int i = 0; i < m_splits.size (); ++i)
{
/* Compute the height and clamp to the allowable range. */
- info[i].height = available_height * m_splits[i].weight / total_weight;
- if (info[i].height > info[i].max_height)
- info[i].height = info[i].max_height;
- if (info[i].height < info[i].min_height)
- info[i].height = info[i].min_height;
- /* If there is any leftover height, just redistribute it to the
+ info[i].size = available_size * m_splits[i].weight / total_weight;
+ if (info[i].size > info[i].max_size)
+ info[i].size = info[i].max_size;
+ if (info[i].size < info[i].min_size)
+ info[i].size = info[i].min_size;
+ /* If there is any leftover size, just redistribute it to the
last resizeable window, by dropping it from the allocated
- height. We could try to be fancier here perhaps, by
- redistributing this height among all windows, not just the
+ size. We could try to be fancier here perhaps, by
+ redistributing this size among all windows, not just the
last window. */
- if (info[i].min_height != info[i].max_height)
+ if (info[i].min_size != info[i].max_size)
{
- used_height += info[i].height;
+ used_size += info[i].size;
if (info[i].share_box)
- --used_height;
+ --used_size;
}
}
- /* Allocate any leftover height. */
- if (available_height >= used_height && last_index != -1)
- info[last_index].height += available_height - used_height;
+ /* Allocate any leftover size. */
+ if (available_size >= used_size && last_index != -1)
+ info[last_index].size += available_size - used_size;
/* Step 3: Resize. */
- int height_accum = 0;
+ int size_accum = 0;
+ const int maximum = m_vertical ? height : width;
for (int i = 0; i < m_splits.size (); ++i)
{
/* If we fall off the bottom, just make allocations overlap.
GIGO. */
- if (height_accum + info[i].height > height)
- height_accum = height - info[i].height;
+ if (size_accum + info[i].size > maximum)
+ size_accum = maximum - info[i].size;
else if (info[i].share_box)
- --height_accum;
- m_splits[i].layout->apply (x, y + height_accum, width, info[i].height);
- height_accum += info[i].height;
+ --size_accum;
+ if (m_vertical)
+ m_splits[i].layout->apply (x, y + size_accum, width, info[i].size);
+ else
+ m_splits[i].layout->apply (x + size_accum, y, info[i].size, height);
+ size_accum += info[i].size;
}
m_applied = true;
@@ -716,6 +746,9 @@ tui_layout_split::specification (ui_file *output, int depth)
if (depth > 0)
fputs_unfiltered ("{", output);
+ if (!m_vertical)
+ fputs_unfiltered ("-horizontal ", output);
+
bool first = true;
for (auto &item : m_splits)
{
@@ -839,8 +872,13 @@ tui_new_layout_command (const char *spec, int from_tty)
if (new_name[0] == '-')
error (_("Layout name cannot start with '-'"));
+ bool is_vertical = true;
+ spec = skip_spaces (spec);
+ if (check_for_argument (&spec, "-horizontal"))
+ is_vertical = false;
+
std::vector<std::unique_ptr<tui_layout_split>> splits;
- splits.emplace_back (new tui_layout_split);
+ splits.emplace_back (new tui_layout_split (is_vertical));
std::unordered_set<std::string> seen_windows;
while (true)
{
@@ -850,8 +888,11 @@ tui_new_layout_command (const char *spec, int from_tty)
if (spec[0] == '{')
{
- splits.emplace_back (new tui_layout_split);
- ++spec;
+ is_vertical = true;
+ spec = skip_spaces (spec + 1);
+ if (check_for_argument (&spec, "-horizontal"))
+ is_vertical = false;
+ splits.emplace_back (new tui_layout_split (is_vertical));
continue;
}
@@ -940,12 +981,12 @@ Usage: layout prev | next | LAYOUT-NAME"),
add_cmd ("new-layout", class_tui, tui_new_layout_command,
_("Create a new TUI layout.\n\
-Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
+Usage: tui new-layout [-horizontal] NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
Create a new TUI layout. The new layout will be named NAME,\n\
and can be accessed using \"layout NAME\".\n\
The windows will be displayed in the specified order.\n\
A WINDOW can also be of the form:\n\
- { NAME WEIGHT [NAME WEIGHT]... }\n\
+ { [-horizontal] NAME WEIGHT [NAME WEIGHT]... }\n\
This form indicates a sub-frame.\n\
Each WEIGHT is an integer, which holds the relative size\n\
to be allocated to the window."),
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 969e4df..6607e8d 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -58,8 +58,9 @@ public:
/* Change the size and location of this layout. */
virtual void apply (int x, int y, int width, int height) = 0;
- /* Return the minimum and maximum height of this layout. */
- virtual void get_sizes (int *min_height, int *max_height) = 0;
+ /* Return the minimum and maximum height or width of this layout.
+ HEIGHT is true to fetch height, false to fetch width. */
+ virtual void get_sizes (bool height, int *min_value, int *max_value) = 0;
/* True if the topmost item in this layout is boxed. */
virtual bool top_boxed_p () const = 0;
@@ -142,7 +143,7 @@ public:
protected:
- void get_sizes (int *min_height, int *max_height) override;
+ void get_sizes (bool height, int *min_value, int *max_value) override;
private:
@@ -159,7 +160,12 @@ class tui_layout_split : public tui_layout_base
{
public:
- tui_layout_split () = default;
+ /* Create a new layout. If VERTICAL is true, then windows in this
+ layout will be arranged vertically. */
+ explicit tui_layout_split (bool vertical = true)
+ : m_vertical (vertical)
+ {
+ }
DISABLE_COPY_AND_ASSIGN (tui_layout_split);
@@ -191,7 +197,7 @@ public:
protected:
- void get_sizes (int *min_height, int *max_height) override;
+ void get_sizes (bool height, int *min_value, int *max_value) override;
private:
@@ -209,6 +215,9 @@ private:
/* The splits. */
std::vector<split> m_splits;
+ /* True if the windows in this split are arranged vertically. */
+ bool m_vertical;
+
/* True if this layout has already been applied at least once. */
bool m_applied = false;
};
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index 8cc0021..ef78e91 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -952,6 +952,14 @@ tui_win_info::max_height () const
return tui_term_height () - 2;
}
+/* See tui-data.h. */
+
+int
+tui_gen_win_info::max_width () const
+{
+ return tui_term_width () - 2;
+}
+
static void
parse_scrolling_args (const char *arg,
struct tui_win_info **win_to_scroll,