From c12cc596ed805cc863eff0076d060815ae830921 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Fri, 16 Oct 2015 00:34:18 +0000 Subject: [PATCH] More general fixes to the tree view and BoxedPanel. llvm-svn: 250478 --- lldb/test/lldbcurses.py | 183 +++++++++++++++++++++++++++++++++------- 1 file changed, 151 insertions(+), 32 deletions(-) diff --git a/lldb/test/lldbcurses.py b/lldb/test/lldbcurses.py index 4f190adb44ad..a5d5c4418906 100644 --- a/lldb/test/lldbcurses.py +++ b/lldb/test/lldbcurses.py @@ -12,6 +12,12 @@ class Point(object): def __str__(self): return "(x=%u, y=%u)" % (self.x, self.y) + + def __eq__(self, rhs): + return self.x == rhs.x and self.y == rhs.y + + def __ne__(self, rhs): + return self.x != rhs.x or self.y != rhs.y def is_valid_coordinate(self): return self.x >= 0 and self.y >= 0 @@ -27,6 +33,12 @@ class Size(object): def __str__(self): return "(w=%u, h=%u)" % (self.w, self.h) + def __eq__(self, rhs): + return self.w == rhs.w and self.h == rhs.h + + def __ne__(self, rhs): + return self.w != rhs.w or self.h != rhs.h + class Rect(object): def __init__(self, x=0, y=0, w=0, h=0): self.origin = Point(x, y) @@ -57,6 +69,12 @@ class Rect(object): return pt.y >= self.get_min_y() return False + def __eq__(self, rhs): + return self.origin == rhs.origin and self.size == rhs.size + + def __ne__(self, rhs): + return self.origin != rhs.origin or self.size != rhs.size + class QuitException(Exception): def __init__(self): super(QuitException, self).__init__('QuitException') @@ -74,7 +92,47 @@ class Window(object): def add_child(self, window): self.children.append(window) window.parent = self + + def resize(self, size): + self.window.resize(size.h, size.w) + def resize_child(self, child, delta_size, adjust_neighbors): + if child in self.children: + frame = self.get_frame() + orig_frame = child.get_frame() + new_frame = Rect(x=orig_frame.origin.x, y=orig_frame.origin.y, w=orig_frame.size.w + delta_size.w, h=orig_frame.size.h + delta_size.h) + old_child_max_x = orig_frame.get_max_x() + new_child_max_x = new_frame.get_max_x() + window_max_x = frame.get_max_x() + if new_child_max_x < window_max_x: + child.resize(new_frame.size) + if old_child_max_x == window_max_x: + new_frame.origin.x += window_max_x - new_child_max_x + child.set_position(new_frame.origin) + elif new_child_max_x > window_max_x: + new_frame.origin.x -= new_child_max_x - window_max_x + child.set_position(new_frame.origin) + child.resize(new_frame.size) + + if adjust_neighbors: + #print 'orig_frame = %s\r\n' % (str(orig_frame)), + for curr_child in self.children: + if curr_child is child: + continue + curr_child_frame = curr_child.get_frame() + if delta_size.w != 0: + #print 'curr_child_frame = %s\r\n' % (str(curr_child_frame)), + if curr_child_frame.get_min_x() == orig_frame.get_max_x(): + curr_child_frame.origin.x += delta_size.w + curr_child_frame.size.w -= delta_size.w + #print 'adjusted curr_child_frame = %s\r\n' % (str(curr_child_frame)), + curr_child.resize (curr_child_frame.size) + curr_child.slide_position (Size(w=delta_size.w, h=0)) + elif curr_child_frame.get_max_x() == orig_frame.get_min_x(): + curr_child_frame.size.w -= delta_size.w + #print 'adjusted curr_child_frame = %s\r\n' % (str(curr_child_frame)), + curr_child.resize (curr_child_frame.size) + def add_key_action(self, arg, callback, decription): if isinstance(arg, list): for key in arg: @@ -270,6 +328,15 @@ class Window(object): size = self.get_size() return Rect(x=position.x, y=position.y, w=size.w, h=size.h) + def get_frame_in_parent(self): + position = self.get_position_in_parent() + size = self.get_size() + return Rect(x=position.x, y=position.y, w=size.w, h=size.h) + + def get_position_in_parent(self): + (y, x) = self.window.getparyx() + return Point(x, y) + def get_position(self): (y, x) = self.window.getbegyx() return Point(x, y) @@ -349,6 +416,16 @@ class Window(object): done = False while not done and n > 0: c = self.window.getch() + if c == 27: + self.timeout(0) + escape_key = 0 + while True: + escape_key = self.window.getch() + if escape_key == -1: + break + else: + c = c << 8 | escape_key + self.timeout(timeout_msec) if c != -1: try: self.handle_key(c) @@ -377,10 +454,10 @@ class Panel(Window): def set_position(self, pt): self.panel.move(pt.y, pt.x) - def slide_position(self, pt): + def slide_position(self, size): new_position = self.get_position() - new_position.x = new_position.x + pt.x - new_position.y = new_position.y + pt.y + new_position.x = new_position.x + size.w + new_position.y = new_position.y + size.h self.set_position(new_position) class BoxedPanel(Panel): @@ -394,6 +471,8 @@ class BoxedPanel(Panel): self.add_key_action(curses.KEY_DOWN, self.select_next, "Select the next item") self.add_key_action(curses.KEY_HOME, self.scroll_begin, "Go to the beginning of the list") self.add_key_action(curses.KEY_END, self.scroll_end, "Go to the end of the list") + self.add_key_action(0x1b4f48, self.scroll_begin, "Go to the beginning of the list") + self.add_key_action(0x1b4f46, self.scroll_end, "Go to the end of the list") self.add_key_action(curses.KEY_PPAGE, self.scroll_page_backward, "Scroll to previous page") self.add_key_action(curses.KEY_NPAGE, self.scroll_page_forward, "Scroll to next forward") self.update() @@ -436,6 +515,14 @@ class BoxedPanel(Panel): if update: self.update() + def scroll_to_line (self, idx): + if idx < len(self.lines): + self.selected_idx = idx + max_visible_lines = self.get_usable_height() + if idx < self.first_visible_idx or idx >= self.first_visible_idx + max_visible_lines: + self.first_visible_idx = idx + self.refresh() + def scroll_begin (self): self.first_visible_idx = 0 if len(self.lines) > 0: @@ -521,12 +608,25 @@ class BoxedPanel(Panel): is_selected = line_idx == self.selected_idx if is_selected: self.attron (curses.A_REVERSE) - self.addnstr_at_point(pt, self.lines[line_idx], max_width) + self.move(pt) + self.addnstr(self.lines[line_idx], max_width) if is_selected: self.attroff (curses.A_REVERSE) else: return + def load_file(self, path): + f = open(path) + if f: + self.lines = f.read().splitlines() + for (idx, line) in enumerate(self.lines): + # Remove any tabs from lines since they hose up the display + if "\t" in line: + self.lines[idx] = (8*' ').join(line.split('\t')) + self.selected_idx = 0 + self.first_visible_idx = 0 + self.refresh() + class Item(object): def __init__(self, title, action): self.title = title @@ -549,6 +649,9 @@ class TreeItemDelegate(object): def draw_item(self, tree_window, item): self.draw_item_string(tree_window, item, item.title) + + def do_action(self): + pass class TreeItem(object): def __init__(self, delegate, parent = None, title = None, action = None, is_expanded = False): @@ -608,8 +711,9 @@ class TreeItem(object): rows = 1 if self.is_expanded: children = self.get_children() - for child in children: - rows += child.get_num_visible_rows() + if children: + for child in children: + rows += child.get_num_visible_rows() return rows def draw(self, tree_window, row): display_row = tree_window.get_display_row(row) @@ -621,8 +725,12 @@ class TreeItem(object): tree_window.addch (curses.ACS_DIAMOND) tree_window.addch (curses.ACS_HLINE) elif self.parent and self.parent.children_might_have_children(): - tree_window.addch (curses.ACS_HLINE) - tree_window.addch (curses.ACS_HLINE) + if self.parent.parent: + tree_window.addch (curses.ACS_HLINE) + tree_window.addch (curses.ACS_HLINE) + else: + tree_window.addch (' ') + tree_window.addch (' ') is_selected = tree_window.is_selected(row) if is_selected: tree_window.attron (curses.A_REVERSE) @@ -650,8 +758,8 @@ class TreeItem(object): tree_window.addch (curses.ACS_VLINE) tree_window.addch (' ') - def was_selected(self): - pass + def was_selected(self): + self.delegate.do_action() class TreePanel(Panel): def __init__(self, frame, title, root_item): @@ -665,8 +773,10 @@ class TreePanel(Panel): self.add_key_action(curses.KEY_DOWN, self.select_next, "Select the next item") self.add_key_action(curses.KEY_RIGHT,self.right_arrow, "Expand an item") self.add_key_action(curses.KEY_LEFT, self.left_arrow, "Unexpand an item or navigate to parent") - self.add_key_action(curses.KEY_HOME, self.scroll_begin, "Go to the beginning of the list") - self.add_key_action(curses.KEY_END, self.scroll_end, "Go to the end of the list") + self.add_key_action(curses.KEY_HOME, self.scroll_begin, "Go to the beginning of the tree") + self.add_key_action(curses.KEY_END, self.scroll_end, "Go to the end of the tree") + self.add_key_action(0x1b4f48, self.scroll_begin, "Go to the beginning of the tree") + self.add_key_action(0x1b4f46, self.scroll_end, "Go to the end of the tree") self.add_key_action(curses.KEY_PPAGE, self.scroll_page_backward, "Scroll to previous page") self.add_key_action(curses.KEY_NPAGE, self.scroll_page_forward, "Scroll to next forward") @@ -717,12 +827,9 @@ class TreePanel(Panel): def is_selected(self, row): return row == self.selected_idx - def get_num_lines(self): - rows = 0 - children = self.root_item.get_children() - for child in children: - rows += child.get_num_visible_rows() - return rows + def get_num_lines(self): + self.get_visible_items() + return len(self.items) def get_num_visible_lines(self): return self.get_size().h-2 @@ -730,7 +837,8 @@ class TreePanel(Panel): self.selected_idx += 1 num_lines = self.get_num_lines() if self.selected_idx >= num_lines: - self.selected_idx = num_lines - 1 + self.selected_idx = num_lines - 1 + self._selection_changed() self.refresh() def select_prev (self): @@ -741,6 +849,7 @@ class TreePanel(Panel): self.selected_idx = 0 else: self.selected_idx = -1 + self._selection_changed() self.refresh() def scroll_begin (self): @@ -750,7 +859,7 @@ class TreePanel(Panel): self.selected_idx = 0 else: self.selected_idx = -1 - self.update() + self.refresh() def redisplay_tree(self): self.items = None @@ -775,35 +884,45 @@ class TreePanel(Panel): def scroll_end (self): num_visible_lines = self.get_num_visible_lines() - num_lines = len(self.lines) + num_lines = self.get_num_lines() if num_lines > num_visible_lines: self.first_visible_idx = num_lines - num_visible_lines else: self.first_visible_idx = 0 self.selected_idx = num_lines-1 - self.update() + self.refresh() def scroll_page_backward(self): num_visible_lines = self.get_num_visible_lines() - new_index = self.first_visible_idx - num_visible_lines + new_index = self.selected_idx - num_visible_lines if new_index < 0: - self.first_visible_idx = 0 + self.selected_idx = 0 else: - self.first_visible_idx = new_index + self.selected_idx = new_index + self._selection_changed() self.refresh() def scroll_page_forward(self): + num_lines = self.get_num_lines() num_visible_lines = self.get_num_visible_lines() - self.first_visible_idx += num_visible_lines - self._adjust_first_visible_line() + new_index = self.selected_idx + num_visible_lines + if new_index >= num_lines: + new_index = num_lines - 1 + self.selected_idx = new_index + self._selection_changed() self.refresh() - def _adjust_first_visible_line(self): - num_lines = len(self.lines) + def _selection_changed(self): + num_lines = self.get_num_lines() num_visible_lines = self.get_num_visible_lines() - if (self.first_visible_idx >= num_lines) or (num_lines - self.first_visible_idx) > num_visible_lines: - self.first_visible_idx = num_lines - num_visible_lines - + last_visible_index = self.first_visible_idx + num_visible_lines + if self.selected_idx >= last_visible_index: + self.first_visible_idx += (self.selected_idx - last_visible_index + 1) + if self.selected_idx < self.first_visible_idx: + self.first_visible_idx = self.selected_idx + if self.selected_idx >= 0 and self.selected_idx < len(self.items): + item = self.items[self.selected_idx] + item.was_selected() class Menu(BoxedPanel):