Repos / mcross / 3a52c77137
commit 3a52c77137265200339be92ade9cd6abc0567f05
Author: Bùi Thành Nhân <hi@imnhan.com>
Date: Fri May 15 15:43:32 2020 +0700
implement history + back/forward buttons
diff --git a/README.md b/README.md
index fad4930..ea00469 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ # Deps
# Feature checklist
-- [ ] back-forward buttons
+- [x] back-forward buttons
- [ ] separate I/O thread to avoid blocking GUI
- [ ] more visual indicators - maybe a status bar at the bottom
- [ ] parse gemini's advanced line types
diff --git a/pyproject.toml b/pyproject.toml
index eaf1700..29d7446 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mcross"
-version = "0.2.1"
+version = "0.3.0"
description = "Do you remember www?"
authors = ["nhanb <hi@imnhan.com>"]
license = "MIT"
diff --git a/src/mcross/gui/controller.py b/src/mcross/gui/controller.py
index 3f1dca9..672e8fd 100644
--- a/src/mcross/gui/controller.py
+++ b/src/mcross/gui/controller.py
@@ -18,6 +18,8 @@ def __init__(self):
self.view = View(self.root, self.model)
self.view.go_callback = self.go_callback
self.view.link_click_callback = self.link_click_callback
+ self.view.back_callback = self.back_callback
+ self.view.forward_callback = self.forward_callback
def run(self):
self.root.title("McRoss Browser")
@@ -33,7 +35,7 @@ def go_callback(self, url: str):
def link_click_callback(self, raw_url):
# FIXME ugh
try:
- url = GeminiUrl.parse(raw_url, self.model.current_url)
+ url = GeminiUrl.parse(raw_url, self.model.history.get_current_url())
self.visit_link(url)
except NonAbsoluteUrlWithoutContextError:
messagebox.showwarning(
@@ -51,6 +53,21 @@ def link_click_callback(self, raw_url):
)
def visit_link(self, url: GeminiUrl):
+ self.load_page(url)
+ self.model.history.visit(url)
+ self.view.render_page()
+
+ def back_callback(self):
+ self.model.history.go_back()
+ self.load_page(self.model.history.get_current_url())
+ self.view.render_page()
+
+ def forward_callback(self):
+ self.model.history.go_forward()
+ self.load_page(self.model.history.get_current_url())
+ self.view.render_page()
+
+ def load_page(self, url: GeminiUrl):
print("Requesting", url)
resp = get(url)
print("Received", resp)
@@ -67,5 +84,3 @@ def visit_link(self, url: GeminiUrl):
]
)
)
- self.model.current_url = url
- self.view.render_page()
diff --git a/src/mcross/gui/model.py b/src/mcross/gui/model.py
index 5164785..4549ba1 100644
--- a/src/mcross/gui/model.py
+++ b/src/mcross/gui/model.py
@@ -1,4 +1,7 @@
+from typing import List
+
from .. import document
+from ..transport import GeminiUrl
DEMO_TEXT = """\
# Welcome to McRoss Browser
@@ -33,12 +36,49 @@
"""
+class History:
+ h: List[GeminiUrl]
+ current_index: int
+
+ def __init__(self):
+ self.h = []
+ self.current_index = None
+
+ def visit(self, url: GeminiUrl):
+ # remove forward history first:
+ if self.current_index is not None:
+ self.h = self.h[: self.current_index + 1]
+ self.h.append(url)
+ self.current_index = len(self.h) - 1
+
+ def go_back(self):
+ if self.can_go_back():
+ self.current_index -= 1
+
+ def go_forward(self):
+ if self.can_go_forward():
+ self.current_index += 1
+
+ def can_go_back(self):
+ return self.current_index not in [None, 0]
+
+ def can_go_forward(self):
+ return self.current_index is not None and self.current_index < len(self.h) - 1
+
+ def get_current_url(self):
+ try:
+ return self.h[self.current_index]
+ except (IndexError, TypeError):
+ return None
+
+
class Model:
- current_url = None
plaintext = ""
gemini_nodes = None
+ history: History
def __init__(self):
+ self.history = History()
self.update_content(DEMO_TEXT)
def update_content(self, plaintext):
diff --git a/src/mcross/gui/view.py b/src/mcross/gui/view.py
index e8a8840..cb74883 100644
--- a/src/mcross/gui/view.py
+++ b/src/mcross/gui/view.py
@@ -24,15 +24,20 @@ def pick_font(names):
class View:
model: Model
address_bar: ttk.Entry
- go_button: ttk.Button
+ go_btn: ttk.Button
+ back_btn: ttk.Button
+ forward_btn: ttk.Button
text: Text
go_callback = None
+ link_click_callback = None
+ back_callback = None
+ forward_callback = None
def __init__(self, root: Tk, model: Model):
self.model = model
- # first row - address bar + button
+ # first row - address bar + buttons
row1 = ttk.Frame(root)
row1.pack(fill="x")
@@ -40,6 +45,18 @@ def __init__(self, root: Tk, model: Model):
row2 = ttk.Frame(root)
row2.pack(fill="both", expand=True)
+ # Back/Forward buttons
+ back_btn = ttk.Button(
+ row1, text="🡄", width=3, command=lambda: self.back_callback()
+ )
+ forward_btn = ttk.Button(
+ row1, text="🡆", width=3, command=lambda: self.forward_callback()
+ )
+ back_btn.pack(side="left", padx=2)
+ forward_btn.pack(side="left", padx=2)
+ self.back_btn = back_btn
+ self.forward_btn = forward_btn
+
# Address bar prefix
address_prefix = ttk.Label(row1, text="gemini://")
address_prefix.pack(side="left")
@@ -53,9 +70,9 @@ def __init__(self, root: Tk, model: Model):
address_bar.focus_set()
# Go button
- go_button = ttk.Button(row1, text="go", command=self._on_go)
- self.go_button = go_button
- go_button.pack(side="left", pady=3)
+ go_btn = ttk.Button(row1, text="go", command=self._on_go)
+ self.go_btn = go_btn
+ go_btn.pack(side="left", pady=3)
# Main viewport implemented as a Text widget.
text = ReadOnlyText(row2)
@@ -119,10 +136,19 @@ def _on_link_click(self, ev):
self.link_click_callback(raw_url)
def render_page(self):
+ # Enable/Disable forward/back buttons according to history
+ self.back_btn.config(
+ state="normal" if self.model.history.can_go_back() else "disabled"
+ )
+ self.forward_btn.config(
+ state="normal" if self.model.history.can_go_forward() else "disabled"
+ )
+
# Update url in address bar
- if self.model.current_url is not None:
+ current_url = self.model.history.get_current_url()
+ if current_url is not None:
self.address_bar.delete(0, "end")
- self.address_bar.insert(0, self.model.current_url.without_protocol())
+ self.address_bar.insert(0, current_url.without_protocol())
# Update viewport
self.text.delete("1.0", "end")