diff --git a/Apps/Terminal/main.vp b/Apps/Terminal/main.vp index 649b322..52cf245 100644 --- a/Apps/Terminal/main.vp +++ b/Apps/Terminal/main.vp @@ -56,9 +56,9 @@ export def _start() -> int: elif act == 5: aval: int = sbar.action_value if term.line_count > 0: - term.scroll_offset = aval * term.line_count / 1000 + term.scroll_offset = aval * (term.line_count + 1) / 1000 vis3: int = term._visible_lines() - max_off: int = term.line_count - vis3 + max_off: int = term.line_count + 1 - vis3 if max_off < 0: max_off = 0 if term.scroll_offset < 0: term.scroll_offset = 0 if term.scroll_offset > max_off: term.scroll_offset = max_off @@ -144,6 +144,28 @@ export def _start() -> int: j += 1 *(dst + out_len) = char(0) + # 提示符 = 归一化路径 + "/> ":根目录显示 "/> ",/apps 显示 "/apps/> "。 + def _update_prompt(): + p: [80]char + i: int = 0 + while i < 63: + ch: char = _cwd[i] + p[i] = ch + if ch == 0: break + i += 1 + if i == 0: + p[0] = char(47) + i = 1 + if p[i - 1] != char(47): + p[i] = char(47) + i += 1 + p[i] = char(62) # '>' + i += 1 + p[i] = char(32) # ' ' + i += 1 + p[i] = char(0) + term.set_prompt(&p[0]) + def _cmd_cd(path: str): # 裸 cd:只显示当前路径,不切换目录(切换请用 cd )。 if path is None or *path == 0: @@ -158,6 +180,7 @@ export def _start() -> int: fs.closedir(dd) # 存入归一化后的路径:根目录的 ".." 保持为 "/",pwd 也保持干净。 _normalize_path(&_cwd[0], 64, &full[0]) + _update_prompt() def _cmd_ls(): dd: int = fs.opendir(&_cwd[0]) @@ -359,6 +382,7 @@ export def _start() -> int: term.insert("Unknown command. Type 'help'.") return 0 + _update_prompt() term.on_command = _on_command root.mainloop() diff --git a/vpsdk/vpui.vp b/vpsdk/vpui.vp index c60ac2d..e3d48c6 100644 --- a/vpsdk/vpui.vp +++ b/vpsdk/vpui.vp @@ -1197,6 +1197,7 @@ virtual class Text(Widget): input_buf: [80]char input_len: int cursor_pos: int + prompt: [80]char bg_color: uint32 text_color: uint32 prompt_color: uint32 @@ -1223,6 +1224,9 @@ virtual class Text(Widget): self.line_count = 0 self.input_len = 0 self.cursor_pos = 0 + self.prompt[0] = '>' + self.prompt[1] = ' ' + self.prompt[2] = 0 self.bg_color = uint32(0x0C0C0C) self.text_color = uint32(0xCCCCCC) self.prompt_color = uint32(0x00FF00) @@ -1250,13 +1254,19 @@ virtual class Text(Widget): line_idx: int = self.scroll_offset + i if line_idx < self.line_count: _draw_text(fb, fw, fh, self.x + 4, self.y + i * CHAR_H, &self.lines[line_idx][0], self.text_color) - prompt_y: int = self.y + self.h - CHAR_H - 4 - _draw_text(fb, fw, fh, self.x + 4, prompt_y, "> ", self.prompt_color) - if self.input_len > 0: - _draw_text(fb, fw, fh, self.x + 4 + 2 * CHAR_W, prompt_y, &self.input_buf[0], uint32(0xFFFFFF)) - cx_pos: int = self.x + 4 + (2 + self.cursor_pos) * CHAR_W - if cx_pos < self.x + self.w - 4: - _fill_rect(fb, fw, fh, cx_pos, prompt_y, CHAR_W // 2, CHAR_H, self.cursor_color) + # 输入行不是一个固定在底部的控件,而是紧跟在最后一条输出之后的一行; + # 输出增多时它随之下移,超出可视区时由 scroll_offset 把它保持在最后一行。 + prompt_row: int = self.line_count - self.scroll_offset + if prompt_row >= 0 and prompt_row < visible: + prompt_y: int = self.y + prompt_row * CHAR_H + plen: int = int(string.strlen(&self.prompt[0])) + _draw_text(fb, fw, fh, self.x + 4, prompt_y, &self.prompt[0], self.prompt_color) + if self.input_len > 0: + _draw_text(fb, fw, fh, self.x + 4 + plen * CHAR_W, prompt_y, + &self.input_buf[0], uint32(0xFFFFFF)) + cx_pos: int = self.x + 4 + (plen + self.cursor_pos) * CHAR_W + if cx_pos < self.x + self.w - 4: + _fill_rect(fb, fw, fh, cx_pos, prompt_y, CHAR_W // 2, CHAR_H, self.cursor_color) def handle_event(self, evt: window.InputEvent*) -> int: etype: uint32 = evt.type @@ -1268,9 +1278,11 @@ virtual class Text(Widget): self.focused = 1 tk: Tk* = self.tk tk.focused_widget = Widget*(self) - prompt_y: int = self.y + self.h - CHAR_H - 4 - if ey >= prompt_y and ey < prompt_y + CHAR_H: - rel_x: int = ex - self.x - 4 - 2 * CHAR_W + prompt_row: int = self.line_count - self.scroll_offset + prompt_y: int = self.y + prompt_row * CHAR_H + if prompt_row >= 0 and prompt_row < self._visible_lines() and ey >= prompt_y and ey < prompt_y + CHAR_H: + plen: int = int(string.strlen(&self.prompt[0])) + rel_x: int = ex - self.x - 4 - plen * CHAR_W if rel_x < 0: rel_x = 0 new_pos: int = (rel_x + CHAR_W / 2) / CHAR_W if new_pos > self.input_len: new_pos = self.input_len @@ -1368,7 +1380,7 @@ virtual class Text(Widget): return 1 elif ch == window.VK_NEXT: vis2: int = self._visible_lines() - max_off: int = self.line_count - vis2 + max_off: int = self.line_count + 1 - vis2 if max_off < 0: max_off = 0 if self.scroll_offset < max_off: self.scroll_offset += vis2 @@ -1389,14 +1401,15 @@ virtual class Text(Widget): return 0 def _exec_input(self): - self.insert("> ") + self.insert(&self.prompt[0]) + plen: int = int(string.strlen(&self.prompt[0])) if self.input_len > 0: last: int = self.line_count - 1 j: int = 0 - while j < self.input_len and j < 77: - self.lines[last][2 + j] = self.input_buf[j] + while j < self.input_len and plen + j < 79: + self.lines[last][plen + j] = self.input_buf[j] j += 1 - self.lines[last][2 + j] = 0 + self.lines[last][plen + j] = 0 if self.history_count < 16: for k in range(80): self.history[self.history_count][k] = self.input_buf[k] @@ -1487,8 +1500,9 @@ pop r12""", self.lines[idx][j] = 0 self.line_count += 1 vis: int = self._visible_lines() - if self.line_count > vis: - self.scroll_offset = self.line_count - vis + total: int = self.line_count + 1 # 输出行 + 输入行 + if total > vis: + self.scroll_offset = total - vis else: self.scroll_offset = 0 self._update_scrollbar() @@ -1501,6 +1515,15 @@ pop r12""", def get(self) -> const str: return &self.input_buf[0] + def set_prompt(self, text: const str): + i: int = 0 + while i < 79: + ch: char = *(text + i) + self.prompt[i] = ch + if ch == 0: break + i += 1 + self.prompt[i] = 0 + def config(self, text_color: uint32 = None, bg_color: uint32 = None, prompt_color: uint32 = None, cursor_color: uint32 = None, border_color: uint32 = None): if text_color is not None: self.text_color = text_color @@ -1514,23 +1537,24 @@ pop r12""", self.border_color = border_color def _visible_lines(self) -> int: - return (self.h - CHAR_H - 4) / CHAR_H + return (self.h - 2) / CHAR_H def _update_scrollbar(self): vis: int = self._visible_lines() - if self.line_count <= vis: + total: int = self.line_count + 1 # 输出行 + 输入行 + if total <= vis: self.scroll_offset = 0 else: - max_off: int = self.line_count - vis + max_off: int = total - vis if self.scroll_offset > max_off: self.scroll_offset = max_off if self.yscrollbar is not None: sb: Scrollbar* = Scrollbar*(self.yscrollbar) - if self.line_count <= vis: + if total <= vis: sb.set(0, 1000) else: - first: int = self.scroll_offset * 1000 / self.line_count - last: int = (self.scroll_offset + vis) * 1000 / self.line_count + first: int = self.scroll_offset * 1000 / total + last: int = (self.scroll_offset + vis) * 1000 / total sb.set(first, last) # ---- Tk:主窗口类 = Wm(窗口管理器协议,无字段)+ Misc(公共状态/方法)----