Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.5.0 #9

Merged
merged 5 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

---

* 1.5.0 (2024-12-11)
* Added support for mouse wheel scrolling.
* Added support for page zooming with `CTRL` + mouse wheel.
* Added search toolbar (`CTRL`+`F`).
* Added option to control search toolbar placement (top/bottom) with `--search-position`.

* 1.4.0 (2024-11-12)
* Added screenshot and simplified landing page.
* Added custom context menu for the embedded browser.
Expand Down
16 changes: 14 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ Run any website as standalone desktop application

## Installation

This is regular Python package and is also hosted on [PyPi](https://pypi.org/project/website-as-app/) so
This is regular Python package and is also hosted
on [PyPi](https://pypi.org/project/website-as-app/) so
you can install it as usual. But because this one is supposed to rather act as the application, I
strongly recommend to use [pipx](https://pipx.pypa.io/) to install this tool in isolated environment:
strongly recommend to use [pipx](https://pipx.pypa.io/) to install this tool in isolated
environment:

```bash
$ pipx install website-as-app
Expand Down Expand Up @@ -52,6 +54,10 @@ Available options:
webapp -h
usage: webapp [--profile PROFILE] [--name NAME] [--icon ICON] [--zoom ZOOM] [--no-tray] url

usage: webapp [--profile PROFILE] [--name NAME] [--icon ICON] [--geometry GEOMETRY]
[--zoom ZOOM] [--no-tray] [--minimized] [--allow-multiple]
[--no-custom-webengine] [--search-top] [--version] [--debug] url

Open any website in standalone window (like it's an app)

positional arguments:
Expand All @@ -66,6 +72,8 @@ options:
--no-tray, -t Disables docking app in system tray (closing window quits app)
--minimized, -m Starts app minimized to system tray.
--allow-multiple, -a Allows multiple instances of the app to run on the same profile
--no-custom-webengine Uses built-in QWebEngineView instead of the custom one we use.
--search-top Puts search bar on top of window when activated
--debug, -d Makes app print more debug messages during execution
```

Expand All @@ -82,6 +90,10 @@ to run on the same profile, use `--allow-multiple` switch.
NOTE: `--zoom` accepts fractional values, so you can use i.e. `--zoom 1.25` to scale content up by
25% or `--zoom 0.75` to scale down to 75% of the original size.

## Keyboard shortcuts

* `CTRL` + `F` - opens search bar (close with `ESC` or toolbar's button).

## Notes

This tool doesn't really transforms websites into offline applications. Rather, it focuses
Expand Down
2 changes: 1 addition & 1 deletion websiteapp/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

class Version(Enum):
MAJOR = 1
MINOR = 4
MINOR = 5
PATCH = 0

@classmethod
Expand Down
5 changes: 4 additions & 1 deletion websiteapp/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
#
##################################################################################
"""
import argparse
import importlib.resources as pkg_resources
import os
import re
from typing import Optional

import argparse
from PySide6.QtGui import QIcon


Expand Down Expand Up @@ -106,6 +106,9 @@ def handle_args():
help='Allows multiple instances of the app to run on the same profile')
parser.add_argument('--no-custom-webengine', action='store_true',
help='Uses built-in QWebEngineView instead of the custom one we use.')
parser.add_argument('--search-top', action='store_true',
help='Puts search bar on top of window when activated')

parser.add_argument('--version', '-v', action='store_true',
help='Prints the version of the app and exits')

Expand Down
6 changes: 6 additions & 0 deletions websiteapp/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

from websiteapp.about import About
from websiteapp.const import Const
from websiteapp.toolbar import SearchToolBar, SearchBarPosition
from websiteapp.utils import Utils
from websiteapp.webengine import CustomWebEngineView

Expand Down Expand Up @@ -134,6 +135,11 @@ def __init__(self):
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)

self.search_toolbar = SearchToolBar.setup_for_window(self)

search_position = SearchBarPosition.TOP if self.args.search_top else SearchBarPosition.BOTTOM
self.search_toolbar = SearchToolBar.setup_for_window(self, position=search_position)

def acquire_lock(self) -> bool:
"""
Acquires a lock for the current profile to prevent multiple instances.
Expand Down
40 changes: 39 additions & 1 deletion websiteapp/webengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
# Target file: websiteapp/custom_web_view.py

import re

from PySide6.QtWidgets import QMenu, QApplication, QMessageBox
from PySide6.QtGui import QAction
from PySide6.QtGui import QAction, QWheelEvent
from PySide6.QtWebEngineCore import QWebEnginePage
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtCore import Qt


class CustomWebEngineView(QWebEngineView):
def __init__(self, parent=None, debug=False):
Expand All @@ -32,6 +35,13 @@ def __init__(self, parent=None, debug=False):
self.loadStarted.connect(self.on_load_started)
self.loadFinished.connect(self.on_load_finished)

# Set minimum/maximum zoom factors to prevent extreme zooming
self._min_zoom = 0.25
self._max_zoom = 5.0

# Store current zoom factor
self._current_zoom = 1.0

def on_load_started(self):
"""
Slot called when page load starts.
Expand All @@ -44,6 +54,34 @@ def on_load_finished(self):
"""
self.loading = False

def wheelEvent(self, event: QWheelEvent) -> None:
"""
Handle mouse wheel events for both scrolling and zooming.

Args:
event (QWheelEvent): The wheel event containing scroll information
"""
modifiers = QApplication.keyboardModifiers()

if modifiers & Qt.KeyboardModifier.ControlModifier:
# Handle zooming with Ctrl+wheel
delta = event.angleDelta().y()
if delta > 0:
# Zoom in
new_zoom = min(self._current_zoom * 1.1, self._max_zoom)
else:
# Zoom out
new_zoom = max(self._current_zoom / 1.1, self._min_zoom)

if new_zoom != self._current_zoom:
self._current_zoom = new_zoom
self.setZoomFactor(self._current_zoom)

event.accept()
else:
# Regular scrolling - pass the event to the parent class
super().wheelEvent(event)

def contextMenuEvent(self, event):
menu = QMenu(self)

Expand Down
Loading