Skip to content

Commit 012a1c6

Browse files
authored
Merge pull request #16 from struckchure/develop
Develop
2 parents 1c9f377 + 28503bc commit 012a1c6

File tree

6 files changed

+156
-58
lines changed

6 files changed

+156
-58
lines changed

examples/builder/main.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from melid.router import Route, Router
1414
from melid.store import State
1515
from melid.tailwind import Tailwind, TailwindConfig
16-
from melid.widgets import Button, Input, InputType, Label
16+
from melid.widgets import Button, Input, InputType, Label, Option, Select
1717

1818
tw_cfg = TailwindConfig().extend(colors={"primary": "gold"})
1919
tw = Tailwind(tw_cfg).tw
@@ -73,6 +73,12 @@ def LoginPage():
7373
return Box(
7474
Box(
7575
[
76+
Select(
77+
[Option("Python", 1), Option("Go", 2), Option("TypeScript", 3)],
78+
on_change=print,
79+
style=tw("Select", "rounded-0 p-2 bg-gray-900")
80+
+ tw("Select QAbstractItemView", "px-2 w-full"),
81+
),
7682
Label(
7783
update_title()[0],
7884
style=tw(

examples/store/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ def __init__(self, *args, **kwargs):
2626

2727
self.label = Label(lambda: globalStore.state["count"])
2828

29-
self.increase_button = Button(text="+")
29+
self.increase_button = Button(child="+")
3030
self.increase_button.clicked.connect(
3131
lambda: globalStore.setState({"count": globalStore.state["count"] + 1})
3232
)
3333

34-
self.reduce_button = Button(text="-")
34+
self.reduce_button = Button(child="-")
3535
self.reduce_button.clicked.connect(
3636
lambda: globalStore.setState({"count": globalStore.state["count"] - 1})
3737
)

examples/tailwind/main.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
BASE_DIR = Path(__file__).parent.parent.parent
55
sys.path.append(str(BASE_DIR))
66

7-
from melid.tailwind import Tailwind
7+
from melid.tailwind import Tailwind, TailwindConfig
8+
9+
tw_cfg = TailwindConfig()
10+
tw_cfg.extend(
11+
colors={"primary": "orange"},
12+
variants={"checked": {"type": "pseudo", "pseudo": ":checked"}},
13+
)
814

915
print(
10-
Tailwind().tw(
16+
Tailwind(tw_cfg).tw(
1117
"Button",
12-
"bg-blue-300 text-black hover:bg-blue-500 rounded-md hover:p-sm ml-sm",
18+
"bg-primary border-primary text-black checked:bg-pink-500 hover:bg-blue-500 rounded-md hover:p-sm ml-sm after:w-40",
1319
)
1420
)

melid/store.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,37 @@ def set(self, value):
4949

5050
def subscribe(self, callback: typing.Callable[[typing.Any], None]):
5151
self.updated.connect(callback)
52+
53+
54+
class StatefulWidget:
55+
def state(
56+
self,
57+
state: State,
58+
condition: typing.Union[bool, typing.Callable[[], bool]] = True,
59+
attribute: str = None,
60+
params: typing.Union[typing.List, typing.Dict, typing.Callable] = None,
61+
):
62+
def resolve_params(p):
63+
if callable(p):
64+
return resolve_params(p())
65+
66+
p1 = p if isinstance(p, list) else []
67+
p2 = p if isinstance(p, dict) else {}
68+
69+
return p1, p2
70+
71+
def resolve_condition(c):
72+
if callable(c):
73+
return resolve_condition(c())
74+
75+
return c
76+
77+
def on_state_change():
78+
p1, p2 = resolve_params(params)
79+
80+
if resolve_condition(condition) and attribute and hasattr(self, attribute):
81+
getattr(self, attribute)(*p1, **p2)
82+
83+
state.subscribe(on_state_change)
84+
85+
return self

melid/tailwind/size.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,27 +72,27 @@ def generate_size_utilities(sizes: Dict[str, str]) -> Dict[str, Any]:
7272
}
7373
utilities[f"border-x-{name}"] = {
7474
"declarations": [
75-
{"property": "border-width-left", "value": value},
76-
{"property": "border-width-right", "value": value},
75+
{"property": "border-left-width", "value": value},
76+
{"property": "border-right-width", "value": value},
7777
]
7878
}
7979
utilities[f"border-y-{name}"] = {
8080
"declarations": [
81-
{"property": "border-width-top", "value": value},
82-
{"property": "border-width-bottom", "value": value},
81+
{"property": "border-top-width", "value": value},
82+
{"property": "border-bottom-width", "value": value},
8383
],
8484
}
8585
utilities[f"border-l-{name}"] = {
86-
"declarations": [{"property": "border-width-left", "value": value}]
86+
"declarations": [{"property": "border-left-width", "value": value}]
8787
}
8888
utilities[f"border-r-{name}"] = {
89-
"declarations": [{"property": "border-width-right", "value": value}]
89+
"declarations": [{"property": "border-right-width", "value": value}]
9090
}
9191
utilities[f"border-t-{name}"] = {
92-
"declarations": [{"property": "border-width-top", "value": value}]
92+
"declarations": [{"property": "border-top-width", "value": value}]
9393
}
9494
utilities[f"border-b-{name}"] = {
95-
"declarations": [{"property": "border-width-bottom", "value": value}]
95+
"declarations": [{"property": "border-bottom-width", "value": value}]
9696
}
9797

9898
# Border Radius Utilities

melid/widgets.py

Lines changed: 96 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import enum
22
import types
33
import typing
4+
from dataclasses import dataclass
45

56
from PyQt5 import QtCore, QtGui, QtWidgets
67

7-
from melid.store import State
8+
from melid.store import StatefulWidget
89
from melid.types import AppEvents
910

1011

11-
class Widget(QtWidgets.QGroupBox):
12+
class Widget(QtWidgets.QGroupBox, StatefulWidget):
1213

1314
STYLESHEET_PATH = ""
1415
STYLESHEET_TYPE = "CSS"
@@ -19,8 +20,8 @@ def __init__(
1920
):
2021
super().__init__()
2122

22-
if qt_window_resized:
23-
qt_window_resized.connect(self.onWindowResized)
23+
# if qt_window_resized:
24+
# qt_window_resized.connect(self.onWindowResized)
2425

2526
self.setObjectName(self.__class__.__name__)
2627
self.setContentsMargins(0, 0, 0, 0)
@@ -90,38 +91,6 @@ def onWindowResized(self, size: QtCore.QSize):
9091
def updateStyleSheet(self, style: str):
9192
self.setStyleSheet(self.styleSheet() + "\n%s" % style)
9293

93-
def state(
94-
self,
95-
state: State,
96-
condition: typing.Union[bool, typing.Callable[[], bool]] = True,
97-
attribute: str = None,
98-
params: typing.Union[typing.List, typing.Dict, typing.Callable] = None,
99-
):
100-
def resolve_params(p):
101-
if callable(p):
102-
return resolve_params(p())
103-
104-
p1 = p if isinstance(p, list) else []
105-
p2 = p if isinstance(p, dict) else {}
106-
107-
return p1, p2
108-
109-
def resolve_condition(c):
110-
if callable(c):
111-
return resolve_condition(c())
112-
113-
return c
114-
115-
def on_state_change():
116-
p1, p2 = resolve_params(params)
117-
118-
if resolve_condition(condition) and attribute and hasattr(self, attribute):
119-
getattr(self, attribute)(*p1, **p2)
120-
121-
state.subscribe(on_state_change)
122-
123-
return self
124-
12594

12695
class Label(QtWidgets.QLabel, Widget):
12796
def __init__(self, text: str, style: str = "", *args, **kwargs):
@@ -136,21 +105,25 @@ def __init__(self, text: str, style: str = "", *args, **kwargs):
136105
class Button(QtWidgets.QPushButton, Widget):
137106
def __init__(
138107
self,
139-
text: typing.Optional[typing.Union[str, QtWidgets.QWidget]] = "",
108+
child: typing.Optional[typing.Union[str, QtWidgets.QWidget, QtGui.QIcon]] = "",
140109
on_click: typing.Optional[types.FunctionType] = None,
141110
style: typing.Optional[str] = "",
142111
*args,
143112
**kwargs,
144113
):
145114
super(Button, self).__init__(*args, **kwargs)
146115

147-
if isinstance(text, str):
148-
self.setText(text)
116+
self.setObjectName(self.__class__.__name__)
117+
118+
if child:
119+
if isinstance(child, str):
120+
self.setText(child)
121+
if isinstance(child, QtGui.QIcon):
122+
self.setIcon(child)
149123

150124
if on_click:
151125
self.clicked.connect(lambda: on_click())
152126

153-
self.setObjectName(self.__class__.__name__)
154127
self.setStyleSheet(style)
155128
self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
156129

@@ -182,8 +155,87 @@ def __init__(
182155

183156
self.setObjectName(self.__class__.__name__)
184157
self.setStyleSheet(style)
185-
self.setSizePolicy(
186-
QtWidgets.QSizePolicy(
187-
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
188-
)
158+
159+
160+
class TextArea(QtWidgets.QTextEdit, Widget):
161+
def __init__(
162+
self,
163+
on_change: typing.Optional[typing.Callable] = None,
164+
style: typing.Optional[str] = "",
165+
):
166+
super().__init__()
167+
168+
if on_change:
169+
self.textChanged.connect(on_change)
170+
171+
self.setObjectName(self.__class__.__name__)
172+
self.setStyleSheet(style)
173+
174+
175+
@dataclass
176+
class Option:
177+
label: str
178+
value: typing.Any
179+
180+
181+
class Select(QtWidgets.QComboBox, Widget):
182+
def __init__(
183+
self,
184+
options: typing.Optional[typing.List[Option]] = None,
185+
on_change: typing.Optional[typing.Callable] = None,
186+
style: typing.Optional[str] = "",
187+
):
188+
super().__init__()
189+
190+
if options:
191+
self.addItems(list(map(lambda x: x.label, options)))
192+
193+
if on_change:
194+
self.activated.connect(lambda idx: on_change(options[idx].value))
195+
196+
# Set placeholder text for the combo box
197+
self.setEditable(True)
198+
self.lineEdit().setPlaceholderText("Select an option...")
199+
self.lineEdit().setAlignment(QtCore.Qt.AlignCenter)
200+
self.setEditable(False) # Disable edit after setting placeholder
201+
202+
# Set custom background color and styling using CSS
203+
# self.setStyleSheet(
204+
# """
205+
# QComboBox {
206+
# background-color: #EFEFEF;
207+
# border: 1px solid #AFAFAF;
208+
# padding: 5px;
209+
# border-radius: 5px;
210+
# }
211+
# QComboBox::drop-down {
212+
# subcontrol-origin: padding;
213+
# subcontrol-position: top right;
214+
# width: 20px;
215+
# border-left-width: 1px;
216+
# border-left-color: darkgray;
217+
# border-left-style: solid; /* Just a single line */
218+
# border-top-right-radius: 3px; /* same radius as the QComboBox */
219+
# border-bottom-right-radius: 3px;
220+
# }
221+
# QComboBox::down-arrow {
222+
# image: url(icons/down_arrow.png); /* Custom down-arrow icon */
223+
# }
224+
# QComboBox QAbstractItemView {
225+
# background-color: white;
226+
# selection-background-color: lightgray;
227+
# selection-color: black;
228+
# }
229+
# """
230+
# )
231+
self.setStyleSheet(
232+
style
233+
+ """
234+
Select::drop-down {
235+
subcontrol-origin: padding;
236+
subcontrol-position: top right;
237+
width: 5px;
238+
padding: 5px;
239+
}
240+
"""
189241
)

0 commit comments

Comments
 (0)