Skip to content

Commit 16f9037

Browse files
authored
v0.0.4 Beta 1 (#32)
Aspect Ratio lock when holding shift resizing layers with one of their corner handles Opacity slider for adjusting opacity Layers have colors now Fixed inspector column headers theme not updating Seperated position (x and y) as well as bound boxes (w and h) Added flip geometry support Images now load in the right spot (assets folder) Added anchor point support Fixed add layer dropdown menu theme Fixed language not updating without relaunch Fixed scale not being updated when layer resized using bounds Handles made easier to drag by increasing area for dragging Fixed text layers font size rendering in the preview incorrectly .caml files in the .ca file now has correct indentation Added Discord Rich Presence Merged the appearance tab with the UI tab in settings window Fixed position not updating when moving layer (due to layer being deselected after dragging) Bound handles for resizing layers now syncs with the cursor (same speed and position) Removed open file button as welcome screen replaces it - RIP Message in the inspector when no layer is selected
1 parent 7c4f89e commit 16f9037

21 files changed

Lines changed: 1055 additions & 323 deletions

README.md

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,64 @@
55
<h3>A collection of scripts to edit .ca files, all connected through a GUI powered by hope, dreams, and a bit of code.</h3>
66

77
<h4>Website: https://openposter.pages.dev/</h4>
8+
<h4>Discord Server (500+ members): https://discord.gg/t3abQJjHm6</h4>
89
</div>
910

1011
<!-- back to normal markdown we go -->
11-
## Building
12+
## Getting Started
1213

13-
Install requirements:
14-
````pip3 install -r requirements.txt````
14+
### Prerequisites
1515

16-
To build the OpenPoster app:
17-
```python3 app.py```
16+
Before you begin, ensure you have the following:
17+
18+
- Computer running MacOS, Windows 10/11, or Linux
19+
- [Python](https://www.python.org/downloads/release/python-3119/) (3.11 recommended)
20+
21+
### Setup
22+
23+
1. Fork the repository
24+
2. Clone your fork locally
25+
3. Install requirements:
26+
```
27+
# MacOS:
28+
pip3 install -r requirements.txt
29+
30+
# Windows:
31+
pip install -r requirements.txt
32+
```
33+
4. Run the OpenPoster app:
34+
```
35+
# MacOS:
36+
python3 app.py
37+
38+
# Windows:
39+
python app.py
40+
```
41+
### Compiling:
42+
```
43+
# MacOS:
44+
python3 compile.py
45+
46+
# Windows:
47+
python compile.py
48+
```
1849

1950
## Features
2051

21-
### Inspector
22-
You can just read or edit in the inspector.
52+
**Inspector:**
53+
You can read and edit in the inspector for the layers, such as the name, position, bounds, color, and more.
2354

24-
### Preview
25-
You can see the selected state's layers.
55+
**Canvas:**
56+
You can see supported layers and a preview of what they would look like on your iPhone/iPad once applied. You can also edit the layers in the Canvas such as resizing and rotating layers if you prefer using the Canvas over the Inspector.
2657

27-
### Layers
28-
You can see all the supported layers in the .ca file.
58+
**Layers:**
59+
You can see all the supported layers in the .ca file with the correct file structure. You can also create new basic, text, and image layers.
2960

30-
### Exporting
61+
**Exporting:**
3162
You can save as a new .ca file or a .tendies file, as well as exporting to Nugget directly.
3263

64+
## License
65+
OpenPoster is under the MIT License. You can view it [here.](LICENSE)
66+
67+
## Image
3368
<img width="1527" alt="image" src="https://github.com/user-attachments/assets/2d98df84-6808-4e1d-93d1-13282f42e63c" /><div align="center">

app.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
# when the imposter is sus
55
# from configparser import ConfigParser
66
from gui.config_manager import ConfigManager
7-
from PySide6.QtCore import QTranslator
7+
from PySide6.QtCore import QTranslator, QProcess
88
from PySide6.QtGui import QFileOpenEvent
99
from gui.welcome import WelcomeWindow
1010
from gui.newfile import NewFileDialog
11-
import os
11+
import os, shutil
1212

1313
class OpenPosterApplication(QtWidgets.QApplication):
1414
def __init__(self, *args, **kwargs):
@@ -79,6 +79,10 @@ def event(self, event):
7979
if action[0] == "open":
8080
action_type = "open"
8181
break
82+
if action[0] == "reset":
83+
process = QProcess()
84+
process.startDetached(sys.executable, sys.argv)
85+
sys.exit(0)
8286
if action[0] == "new":
8387
newdlg = NewFileDialog()
8488
newdlg.exec()
6.68 MB
Loading
49.2 KB
Loading
62.8 KB
Loading

assets/OpenPoster.icon/icon.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"fill" : {
3+
"solid" : "extended-gray:1.00000,1.00000"
4+
},
5+
"groups" : [
6+
{
7+
"layers" : [
8+
{
9+
"glass" : false,
10+
"image-name" : "Layer_2-removebg-preview.png",
11+
"name" : "Layer_2-removebg-preview",
12+
"position" : {
13+
"scale" : 2,
14+
"translation-in-points" : [
15+
0,
16+
0
17+
]
18+
}
19+
},
20+
{
21+
"image-name" : "Layer_1-removebg-preview.png",
22+
"name" : "Layer_1-removebg-preview",
23+
"position" : {
24+
"scale" : 2,
25+
"translation-in-points" : [
26+
0,
27+
0
28+
]
29+
}
30+
}
31+
],
32+
"shadow" : {
33+
"kind" : "neutral",
34+
"opacity" : 0.5
35+
},
36+
"translucency" : {
37+
"enabled" : true,
38+
"value" : 0.5
39+
}
40+
}
41+
],
42+
"supported-platforms" : {
43+
"circles" : [
44+
"watchOS"
45+
],
46+
"squares" : "shared"
47+
}
48+
}

gui/_assets.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ def __init__(self):
77
self.cafilepath = ""
88
self.cachedImages = {}
99
self.missing_assets = set()
10+
self.config_dir = os.path.join(os.path.expanduser("~"), ".openposter")
11+
self.assets_cache_dir = os.path.join(self.config_dir, "assets-cache")
1012

1113
if hasattr(sys, '_MEIPASS'):
1214
self.app_base_path = sys._MEIPASS
@@ -18,12 +20,27 @@ def loadImage(self, src_path):
1820
return None
1921

2022
if src_path in self.cachedImages:
23+
print(f"Found image in memory cache: {src_path}")
2124
return self.cachedImages[src_path]
2225

26+
filename = os.path.basename(src_path)
27+
cache_path = os.path.join(self.assets_cache_dir, filename)
28+
if os.path.exists(cache_path):
29+
print(f"Found image directly in assets cache: {cache_path}")
30+
try:
31+
img = QImage(cache_path)
32+
if not img.isNull():
33+
pixmap = QPixmap.fromImage(img)
34+
self.cachedImages[src_path] = pixmap
35+
return pixmap
36+
except Exception as e:
37+
print(f"Error loading cached image {cache_path}: {e}")
38+
2339
asset_path = self.findAssetPath(src_path)
24-
40+
2541
if not asset_path or not os.path.exists(asset_path):
2642
print(f"Could not find asset: {src_path}")
43+
print(f"Checked in assets cache: {cache_path}")
2744

2845
if not hasattr(self, 'missing_assets'):
2946
self.missing_assets = set()
@@ -48,7 +65,20 @@ def loadImage(self, src_path):
4865
def findAssetPath(self, src_path):
4966
if not src_path:
5067
return None
51-
68+
69+
if src_path.startswith("assets/"):
70+
filename = os.path.basename(src_path)
71+
cache_path = os.path.join(self.assets_cache_dir, filename)
72+
if os.path.exists(cache_path):
73+
print(f"Found asset in cache directory: {cache_path}")
74+
return cache_path
75+
76+
filename = os.path.basename(src_path)
77+
cache_path = os.path.join(self.assets_cache_dir, filename)
78+
if os.path.exists(cache_path):
79+
print(f"Found asset in cache by basename: {cache_path}")
80+
return cache_path
81+
5282
if src_path.startswith("themes/") or src_path.startswith("icons/") or src_path.startswith("assets/"):
5383
app_level_path = os.path.join(self.app_base_path, src_path)
5484
if os.path.exists(app_level_path):

gui/_parse.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ def parseColor(self, color_str) -> QColor:
6060

6161
if color_str.startswith("#"):
6262
return QColor(color_str)
63+
if " " in color_str and all(p.replace(".", "", 1).isdigit() for p in color_str.split()):
64+
parts = color_str.split()
65+
r = int(float(parts[0])); g = int(float(parts[1])); b = int(float(parts[2]))
66+
a = float(parts[3]) if len(parts) == 4 else 1.0
67+
return QColor(r, g, b, int(a * 255))
6368
except:
6469
pass
6570

0 commit comments

Comments
 (0)