Skip to content

Commit

Permalink
Move widgets to oterm.app.widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
ggozad committed Jan 10, 2024
1 parent abff8ba commit e6c8803
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 60 deletions.
56 changes: 1 addition & 55 deletions oterm/app/image_browser.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,15 @@
from base64 import b64encode
from io import BytesIO
from pathlib import Path
from typing import Iterable

from PIL import Image as PILImage
from PIL import UnidentifiedImageError
from rich_pixels import Pixels
from textual.app import ComposeResult
from textual.containers import Container, Horizontal, Vertical
from textual.message import Message
from textual.reactive import reactive
from textual.screen import ModalScreen
from textual.widget import Widget
from textual.widgets import DirectoryTree, Label

IMG_MAX_SIZE = 80
IMAGE_EXTENSIONS = PILImage.registered_extensions()


class ImageAdded(Message):
def __init__(self, path: Path, image: str) -> None:
self.path = path
self.image = image
super().__init__()


class Image(Widget):
path: reactive[str] = reactive("")

def __init__(self, id="", classes="") -> None:
self.pixels = None
super().__init__(id=id, classes=classes)

def watch_path(self, path: str) -> None:
if path:
try:
with PILImage.open(path) as img:
max_size = max(img.width, img.height)
width = int(img.width / max_size * IMG_MAX_SIZE)
height = int(img.height / max_size * IMG_MAX_SIZE)

self.set_styles(
f"""
width: {width * 2};
height: {height};
padding:1;
"""
)
self.pixels = Pixels.from_image_path(path, (width, height))
except UnidentifiedImageError:
self.pixels = None
else:
self.pixels = None

def render(self):
if self.pixels:
return self.pixels
return ""


class ImageDirectoryTree(DirectoryTree):
def filter_paths(self, paths: Iterable[Path]) -> Iterable[Path]:
return [
path for path in paths if path.suffix in IMAGE_EXTENSIONS or path.is_dir()
]
from oterm.app.widgets.image import IMAGE_EXTENSIONS, Image, ImageDirectoryTree


class ImageSelect(ModalScreen[tuple[Path, str]]):
Expand Down
2 changes: 1 addition & 1 deletion oterm/app/oterm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from textual.app import App, ComposeResult
from textual.widgets import Footer, Header, TabbedContent, TabPane

from oterm.app.chat import ChatContainer
from oterm.app.model_selection import ModelSelection
from oterm.app.splash import SplashScreen
from oterm.app.widgets.chat import ChatContainer
from oterm.store.store import Store


Expand Down
4 changes: 2 additions & 2 deletions oterm/app/chat.py → oterm/app/widgets/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
)

from oterm.app.chat_rename import ChatRename
from oterm.app.image_browser import ImageAdded
from oterm.app.prompt import FlexibleInput
from oterm.app.widgets.image import ImageAdded
from oterm.app.widgets.prompt import FlexibleInput
from oterm.ollama import OllamaLLM


Expand Down
61 changes: 61 additions & 0 deletions oterm/app/widgets/image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from pathlib import Path
from typing import Iterable

from PIL import Image as PILImage
from PIL import UnidentifiedImageError
from rich_pixels import Pixels
from textual.message import Message
from textual.reactive import reactive
from textual.widget import Widget
from textual.widgets import DirectoryTree

IMG_MAX_SIZE = 80
IMAGE_EXTENSIONS = PILImage.registered_extensions()


class ImageAdded(Message):
def __init__(self, path: Path, image: str) -> None:
self.path = path
self.image = image
super().__init__()


class Image(Widget):
path: reactive[str] = reactive("")

def __init__(self, id="", classes="") -> None:
self.pixels = None
super().__init__(id=id, classes=classes)

def watch_path(self, path: str) -> None:
if path:
try:
with PILImage.open(path) as img:
max_size = max(img.width, img.height)
width = int(img.width / max_size * IMG_MAX_SIZE)
height = int(img.height / max_size * IMG_MAX_SIZE)

self.set_styles(
f"""
width: {width * 2};
height: {height};
padding:1;
"""
)
self.pixels = Pixels.from_image_path(path, (width, height))
except UnidentifiedImageError:
self.pixels = None
else:
self.pixels = None

def render(self):
if self.pixels:
return self.pixels
return ""


class ImageDirectoryTree(DirectoryTree):
def filter_paths(self, paths: Iterable[Path]) -> Iterable[Path]:
return [
path for path in paths if path.suffix in IMAGE_EXTENSIONS or path.is_dir()
]
3 changes: 2 additions & 1 deletion oterm/app/prompt.py → oterm/app/widgets/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
from textual.widget import Widget
from textual.widgets import Button, Input

from oterm.app.image_browser import ImageAdded, ImageSelect
from oterm.app.image_browser import ImageSelect
from oterm.app.widgets.image import ImageAdded
from oterm.app.widgets.text_area import TextArea


Expand Down
2 changes: 1 addition & 1 deletion oterm/store/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import aiosqlite
from packaging.version import parse

from oterm.app.chat import Author
from oterm.app.widgets.chat import Author
from oterm.store.chat import queries as chat_queries
from oterm.store.setup import queries as setup_queries
from oterm.store.upgrades import upgrades
Expand Down

0 comments on commit e6c8803

Please sign in to comment.