Compare commits
No commits in common. "9c79d017ffb9ce501ba0ae3218f2cfa612e88fae" and "a8e667dbce3926a010bce73dbacbea7e0619306b" have entirely different histories.
9c79d017ff
...
a8e667dbce
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
.idea
|
142
doc_manager.py
Normal file
142
doc_manager.py
Normal file
@ -0,0 +1,142 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
import org_rw
|
||||
from org_rw import OrgDoc, OrgTime
|
||||
|
||||
EXTENSIONS = (".org", ".org.txt")
|
||||
|
||||
|
||||
def is_today(ot: OrgTime):
|
||||
now = datetime.now()
|
||||
return (
|
||||
(ot.time.year == now.year)
|
||||
and (ot.time.month == now.month)
|
||||
and (ot.time.day == now.day)
|
||||
)
|
||||
|
||||
|
||||
class Agenda:
|
||||
def __init__(
|
||||
self,
|
||||
/,
|
||||
with_hour: List[org_rw.Headline],
|
||||
no_hour: List[org_rw.Headline],
|
||||
):
|
||||
self.with_hour = with_hour
|
||||
self.no_hour = no_hour
|
||||
|
||||
def print(self):
|
||||
for item in self.with_hour:
|
||||
print(item.scheduled.time, item.state, item.title)
|
||||
|
||||
if len(self.with_hour) > 0:
|
||||
print("--------")
|
||||
|
||||
for item in self.no_hour:
|
||||
print(item.scheduled.time, item.state, item.title)
|
||||
|
||||
|
||||
class DocumentManager:
|
||||
docs: list[OrgDoc]
|
||||
|
||||
def __init__(self, base_path: os.PathLike):
|
||||
self.base_path = base_path
|
||||
|
||||
def load(self):
|
||||
top = os.path.abspath(self.base_path)
|
||||
|
||||
docs = []
|
||||
|
||||
for root, dirs, files in os.walk(top):
|
||||
# Prune dirs
|
||||
i = 0
|
||||
while i < len(dirs):
|
||||
if dirs[i].startswith(".git"):
|
||||
del dirs[i]
|
||||
else:
|
||||
i += 1
|
||||
|
||||
# Process files
|
||||
for name in files:
|
||||
if all(map(lambda ext: not name.endswith(ext), EXTENSIONS)):
|
||||
continue
|
||||
|
||||
path = os.path.join(root, name)
|
||||
|
||||
try:
|
||||
doc = org_rw.load(open(path), extra_cautious=True)
|
||||
docs.append(doc)
|
||||
except Exception as err:
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
print(f"== On {path}")
|
||||
sys.exit(1)
|
||||
|
||||
logging.info("Loaded {} files".format(len(docs)))
|
||||
|
||||
self.docs = docs
|
||||
|
||||
def get_agenda(self) -> Agenda:
|
||||
headline_count = 0
|
||||
items_in_agenda = []
|
||||
now = datetime.now()
|
||||
|
||||
for doc in self.docs:
|
||||
for hl in doc.getAllHeadlines():
|
||||
headline_count += 1
|
||||
|
||||
if hl.scheduled and isinstance(hl.scheduled, OrgTime):
|
||||
if is_today(hl.scheduled):
|
||||
items_in_agenda.append(hl)
|
||||
elif (hl.scheduled.time.to_datetime() < now) and hl.is_todo:
|
||||
items_in_agenda.append(hl)
|
||||
|
||||
logging.info("Read {} items".format(headline_count))
|
||||
logging.info("{} items in agenda today".format(len(items_in_agenda)))
|
||||
|
||||
items_with_hour = [
|
||||
item
|
||||
for item in items_in_agenda
|
||||
if item.scheduled and is_today(item.scheduled) and item.scheduled.time.hour
|
||||
]
|
||||
other_items = [
|
||||
item
|
||||
for item in items_in_agenda
|
||||
if not (
|
||||
item.scheduled and is_today(item.scheduled) and item.scheduled.time.hour
|
||||
)
|
||||
]
|
||||
|
||||
logging.info("{} items today for a specific hour".format(len(items_with_hour)))
|
||||
|
||||
return Agenda(
|
||||
with_hour=sorted(items_with_hour, key=lambda x: x.scheduled.time),
|
||||
no_hour=other_items,
|
||||
)
|
||||
|
||||
def get_notes(self, query) -> List[org_rw.Headline]:
|
||||
headline_count = 0
|
||||
t0 = datetime.now()
|
||||
notes = []
|
||||
query = [q.lower() for q in query]
|
||||
|
||||
for doc in self.docs:
|
||||
for hl in doc.getAllHeadlines():
|
||||
headline_count += 1
|
||||
|
||||
data = "\n".join(hl.get_contents("raw")).lower()
|
||||
if all([q in data for q in query]):
|
||||
notes.append(hl)
|
||||
|
||||
logging.info(
|
||||
"Filtered {} to {} items in {:.3f}s".format(
|
||||
headline_count, len(notes), (datetime.now() - t0).total_seconds()
|
||||
)
|
||||
)
|
||||
|
||||
return notes
|
244
main.py
Normal file → Executable file
244
main.py
Normal file → Executable file
@ -1,60 +1,210 @@
|
||||
from kivy.app import App
|
||||
from kivy.core.window import Window
|
||||
from kivy.modules import inspector
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
from kivy.uix.button import Button
|
||||
from kivy.uix.gridlayout import GridLayout
|
||||
from kivy.uix.scrollview import ScrollView
|
||||
from kivy.uix.textinput import TextInput
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import webbrowser
|
||||
|
||||
from PySide2.QtCore import QObject, QThread, Signal, Slot
|
||||
from PySide2.QtWidgets import (QApplication, QDialog, QFrame, QGroupBox,
|
||||
QHBoxLayout, QLabel, QLineEdit, QProgressBar,
|
||||
QPushButton, QScrollArea, QScroller, QTabBar,
|
||||
QVBoxLayout)
|
||||
|
||||
import doc_manager
|
||||
|
||||
DOCS_PATH = os.environ["ORG_PATH"]
|
||||
|
||||
|
||||
class TestApp(App):
|
||||
class LoadDoneSignal(QObject):
|
||||
sig = Signal(doc_manager.DocumentManager)
|
||||
|
||||
|
||||
class DocumentLoader(QThread):
|
||||
def __init__(self, manager):
|
||||
QThread.__init__(self, None)
|
||||
self.manager = manager
|
||||
self.signal = LoadDoneSignal()
|
||||
|
||||
def run(self):
|
||||
self.manager.load()
|
||||
self.signal.sig.emit(self.manager)
|
||||
|
||||
|
||||
class Dialog(QDialog):
|
||||
def __init__(self):
|
||||
App.__init__(self)
|
||||
self.results = []
|
||||
super(Dialog, self).__init__()
|
||||
|
||||
def on_omnibox_change(self, _instance, value):
|
||||
print("⇒", value)
|
||||
while self.results:
|
||||
btn = self.results.pop()
|
||||
self.layout.remove_widget(btn)
|
||||
self.setWindowTitle("OrgEditor")
|
||||
scrSize = self.screen().size()
|
||||
self.resize(scrSize.width() / 1.5, scrSize.height() / 1.5)
|
||||
self.loader = None
|
||||
self.manager = doc_manager.DocumentManager(DOCS_PATH)
|
||||
|
||||
for i in range(100):
|
||||
btn = Button(text=value + str(i), height=40, size_hint_y=None)
|
||||
self.layout.add_widget(btn)
|
||||
self.results.append(btn)
|
||||
layout = QVBoxLayout()
|
||||
|
||||
def build(self):
|
||||
self.root = BoxLayout(orientation="vertical", spacing=5)
|
||||
# Make sure the height is such that there is something to scroll.
|
||||
self.root.bind(minimum_height=self.root.setter("height"))
|
||||
# Edit box
|
||||
self.progressBar = QProgressBar()
|
||||
self.progressBar.setRange(0, 0) # Make undetermined
|
||||
layout.addWidget(self.progressBar)
|
||||
|
||||
self.omnibox = TextInput(
|
||||
text="",
|
||||
hint_text="Search here files and headlines",
|
||||
multiline=False,
|
||||
write_tab=False,
|
||||
size_hint_y=None,
|
||||
height=40,
|
||||
focus=False,
|
||||
self.edit = QLineEdit("", placeholderText="Search for notes")
|
||||
self.edit.textEdited.connect(self.on_text_edited)
|
||||
layout.addWidget(self.edit)
|
||||
|
||||
layout.setSpacing(0)
|
||||
|
||||
self.results = QScrollArea(widgetResizable=True)
|
||||
layout.addWidget(self.results)
|
||||
QScroller.grabGesture(
|
||||
self.results.viewport(),
|
||||
QScroller.LeftMouseButtonGesture,
|
||||
)
|
||||
self.omnibox.bind(text=self.on_omnibox_change)
|
||||
self.root.add_widget(self.omnibox)
|
||||
|
||||
self.viewer = ScrollView(
|
||||
size_hint=(1, 1), size=(Window.width / 2, Window.height / 2)
|
||||
# Options
|
||||
self.tabBar = QTabBar(shape=QTabBar.RoundedSouth)
|
||||
|
||||
self.tabBar.addTab("Agenda")
|
||||
self.tabBar.addTab("Notes")
|
||||
self.tabBar.addTab("Tasks")
|
||||
self.tabBar.currentChanged.connect(self.update_tab)
|
||||
|
||||
layout.addWidget(self.tabBar)
|
||||
|
||||
self.setLayout(layout)
|
||||
self.startLoad()
|
||||
|
||||
@Slot()
|
||||
def on_text_edited(self):
|
||||
if self.tabBar.currentIndex() != 1:
|
||||
self.tabBar.setCurrentIndex(1)
|
||||
else:
|
||||
self.loadNotes()
|
||||
|
||||
@Slot()
|
||||
def update_tab(self):
|
||||
tabIndex = self.tabBar.currentIndex()
|
||||
if tabIndex == 0:
|
||||
self.loadAgenda()
|
||||
elif tabIndex == 1:
|
||||
self.loadNotes()
|
||||
elif tabIndex == 2:
|
||||
self.loadTasks()
|
||||
|
||||
def startLoad(self):
|
||||
self.edit.setDisabled(True)
|
||||
self.edit.setVisible(False)
|
||||
self.tabBar.setDisabled(True)
|
||||
self.progressBar.setVisible(True)
|
||||
|
||||
self.loader = DocumentLoader(self.manager)
|
||||
self.loader.signal.sig.connect(self.longoperationcomplete)
|
||||
self.loading_start_time = time.time()
|
||||
self.loader.start()
|
||||
|
||||
def endLoad(self):
|
||||
self.edit.setDisabled(False)
|
||||
self.edit.setVisible(True)
|
||||
self.tabBar.setDisabled(False)
|
||||
self.progressBar.setVisible(False)
|
||||
|
||||
self.update_tab()
|
||||
|
||||
def longoperationcomplete(self, data):
|
||||
logging.info(
|
||||
"Loading complete in {:.3f}s".format(time.time() - self.loading_start_time)
|
||||
)
|
||||
self.layout = BoxLayout(orientation="vertical", spacing=2, size_hint_y=None)
|
||||
self.layout.bind(minimum_height=self.layout.setter("height"))
|
||||
for i in range(100):
|
||||
btn = Button(text=str(i), height=40, size_hint_y=None)
|
||||
self.layout.add_widget(btn)
|
||||
self.results.append(btn)
|
||||
self.endLoad()
|
||||
|
||||
self.viewer.add_widget(self.layout)
|
||||
self.root.add_widget(self.viewer)
|
||||
inspector.create_inspector(Window, self.root)
|
||||
return self.root
|
||||
def loadAgenda(self):
|
||||
agenda = self.manager.get_agenda()
|
||||
old = self.results.layout()
|
||||
|
||||
if old:
|
||||
print("Deleting old")
|
||||
old.deleteLater()
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
for item in agenda.with_hour:
|
||||
layout.addWidget(self.build_agenda_task_widget(item))
|
||||
|
||||
# if len(agenda.with_hour) > 0 and len(agenda.no_hour) > 0:
|
||||
# layout.addWidget(QSplitter())
|
||||
|
||||
for item in agenda.no_hour:
|
||||
layout.addWidget(self.build_agenda_task_widget(item))
|
||||
|
||||
frame = QFrame(self.results)
|
||||
frame.setLayout(layout)
|
||||
self.results.setWidget(frame)
|
||||
|
||||
def build_agenda_task_widget(self, item):
|
||||
box = QHBoxLayout()
|
||||
frame = QGroupBox()
|
||||
frame.setLayout(box)
|
||||
|
||||
state_button = QPushButton(text=f"{item.state or '-'}", maximumWidth=60)
|
||||
if item.is_done:
|
||||
state_button.setFlat(True)
|
||||
box.addWidget(state_button)
|
||||
|
||||
box.addWidget(QLabel(text=f"{item.scheduled.time}", maximumWidth=200))
|
||||
box.addWidget(QLabel(text=f"{item.title}"))
|
||||
|
||||
def on_clicked():
|
||||
state_button.setText("DONE")
|
||||
# state_button.setFlat(True)
|
||||
# item.state = 'DONE'
|
||||
|
||||
if not item.is_done:
|
||||
state_button.clicked.connect(on_clicked)
|
||||
|
||||
return frame
|
||||
|
||||
def build_note_task_widget(self, item):
|
||||
box = QHBoxLayout()
|
||||
frame = QGroupBox()
|
||||
frame.setLayout(box)
|
||||
|
||||
titleButton = QPushButton(text=f"{item.title}")
|
||||
box.addWidget(titleButton)
|
||||
|
||||
def on_clicked():
|
||||
webbrowser.open("org-protocol://org-id?id=" + item.id)
|
||||
|
||||
titleButton.clicked.connect(on_clicked)
|
||||
|
||||
return frame
|
||||
|
||||
def loadNotes(self):
|
||||
query = self.edit.text()
|
||||
notes = self.manager.get_notes(query.split())
|
||||
old = self.results.layout()
|
||||
|
||||
if old:
|
||||
print("Deleting old")
|
||||
old.deleteLater()
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
for note in notes:
|
||||
layout.addWidget(self.build_note_task_widget(note))
|
||||
|
||||
frame = QFrame(self.results)
|
||||
frame.setLayout(layout)
|
||||
self.results.setWidget(frame)
|
||||
|
||||
def loadTasks(self):
|
||||
logging.warning("loadTasks not yet implemented")
|
||||
|
||||
|
||||
TestApp().run()
|
||||
# Create the Qt Application
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
dialog = Dialog()
|
||||
sys.exit(dialog.exec_())
|
||||
|
149
org-mode.svg
Normal file
149
org-mode.svg
Normal file
@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="144.98"
|
||||
height="160"
|
||||
viewBox="-7.65 -13.389 144.98 160"
|
||||
version="1.1"
|
||||
id="svg28"
|
||||
sodipodi:docname="org-mode.svg"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
|
||||
<metadata
|
||||
id="metadata34">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs32" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1364"
|
||||
inkscape:window-height="743"
|
||||
id="namedview30"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.066"
|
||||
inkscape:cx="88.23"
|
||||
inkscape:cy="32.52"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="23"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:document-rotation="0" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="Backdrop"
|
||||
style="display:inline">
|
||||
<circle
|
||||
style="opacity:1;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.0067;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:1;paint-order:fill markers stroke"
|
||||
id="path878"
|
||||
cx="66.35"
|
||||
cy="72.64"
|
||||
r="68.86" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Base"
|
||||
style="display:inline">
|
||||
<path
|
||||
fill="#77aa99"
|
||||
stroke="#000000"
|
||||
stroke-width="0.5"
|
||||
d="m 6.448,104.3 c 0,0 10.022,36.1 46.552,24.6 25.19,-7.2 43.25,3 46.11,4.1 l 4.39,-2.5 2.9,-2.1 C 105.8,126.9 102.8,114.6 76.98,99.64 61.72,91.32 71.3,76.99 72.39,71.93 c 0,0 12.23,8.55 21.09,-4.52 8.02,2.06 13.32,-1.47 20.22,1.03 4.2,1.83 21.8,0.72 15.3,-9.11 4.1,-2.68 4.5,-1.81 6.6,-5.9 1.1,-4.95 -1.4,-6.01 -2.2,-7.36 -0.2,-3.15 -2.8,-4.37 -6,-2.13 -7.2,-1.29 -14.3,-0.68 -17.8,-0.98 -7.7,-1.07 -14.03,-5.13 -14.03,-5.13 0.93,-1.24 0.48,-3.91 -5.5,-4.1 -3.29,-1.08 -6.75,-3.13 -9.29,-3.16 -2.57,0 -2.91,-2.54 -2.91,-2.54 -1.61,-0.87 -3.93,-4.25 -3.91,-9.44 0,-3.27 -6.09,0.32 -6.09,6.79 0,6.46 -5.82,7.76 -5.82,7.76 0,0 -2.55,-2.28 -2.86,-5.96 -0.58,-3.79 -4.93,-9.56 -7.05,-2.43 -3.23,7.64 -3.49,9.42 -4.12,13.15 -1.31,7.71 -0.34,8.01 -0.34,8.01 L 14.85,69.34 Z"
|
||||
id="path4"
|
||||
transform="translate(0,0.001)"
|
||||
sodipodi:nodetypes="ccccccccscccccccscsscccsccc" />
|
||||
<path
|
||||
fill="#314b49"
|
||||
stroke="#314b49"
|
||||
stroke-width="0.75"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m 84.11,42.83 c 1.55,-0.56 0.9,-0.41 1.15,-0.58 -2.96,0.58 -9.63,0.62 -14.31,-1.13 0.39,0.23 2.56,0.96 2.84,1.13 0.22,0.71 0.1,1.43 2.93,2.71 2.56,0.79 5.85,0.46 6.84,-0.53 0.11,-1.69 0.12,-1.07 0.55,-1.6 z"
|
||||
id="path6"
|
||||
transform="translate(0,0.001)" />
|
||||
<path
|
||||
fill="#314b49"
|
||||
stroke="#314b49"
|
||||
stroke-width="0.5"
|
||||
d="m 116.5,61.98 c -2.9,-2.09 -4.9,-0.27 -6.5,-0.41 1,-0.65 3.8,-2.07 8.3,-2.07 2.5,0 3.8,2.2 5.5,2.21 1.2,0 4.5,-1.71 5.2,-2.38 -1,0.84 0.4,1.76 -0.5,3.01 -0.3,0.36 -0.9,1.51 -2.7,2.05 -2,0.97 -5.4,1.76 -9.3,-2.41 z"
|
||||
id="path8"
|
||||
transform="translate(0,0.001)" />
|
||||
<path
|
||||
fill="#314b49"
|
||||
d="m 54.93,24.03 c 0,0 -3.35,8 0.31,15.33 3.67,7.34 0.53,-6.83 4.69,-4.16 3.4,0.39 -2.38,-3.21 -2.03,-7.82 -0.18,-2.89 -1.77,-5.19 -2.97,-3.35 z m 64.37,26.39 c 0,1.12 -1.3,2.03 -3,2.03 3.6,-1.12 -0.2,-4.66 -3.1,-2.03 0,-1.12 1.4,-2.03 3.1,-2.03 1.7,0 3,0.91 3,2.03 z"
|
||||
id="path10"
|
||||
transform="translate(0,0.001)" />
|
||||
<path
|
||||
fill="#314b49"
|
||||
d="m 114.2,47.83 c 3.7,-0.23 6.3,0.33 5.5,3.14 0.6,-1.12 1.3,-2.83 -1,-3.51 -1.8,-0.38 -3.3,-0.37 -4.5,0.37 z"
|
||||
id="path12"
|
||||
transform="translate(0,0.001)" />
|
||||
<path
|
||||
fill="#796958"
|
||||
stroke="#000000"
|
||||
stroke-width="0.5"
|
||||
d="m 76.27,30.18 c 0,0 -0.25,7.47 6.72,2.6 3.61,0.1 2.01,-3.86 2.01,-3.86 2.44,-0.68 2.81,-3.85 1.85,-5.71 3.11,0.1 2.61,-4.72 2.18,-6.38 2.44,-0.93 2.77,-3.83 1.77,-6.13 2.93,-0.67 3.02,-4.116 2.77,-6.55 3.02,-0.168 2.6,-5.457 2.6,-6.549 2.6,-1.679 2.02,-3.946 2.42,-6.573 1.61,-3.248 -0.57,-4.178 -2.11,-0.71 -1.65,3.001 -3.77,4.311 -3.75,6.528 0.75,1.259 -5.63,3.106 -3.61,7.052 -1.43,1.763 -4.79,4.03 -3.59,6.732 -0.61,1.33 -4.89,4.43 -3.04,7.37 -4.03,2.69 -3.79,3.34 -2.94,5.79 -2.16,1.38 -4.41,4.14 -3.28,6.39 z"
|
||||
id="path16"
|
||||
transform="translate(0,0.001)" />
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="m 94.09,-5.087 c 0,0 -0.73,1.324 -0.73,2.133 0,0.809 2.18,0.568 2.93,-0.227 -1.63,0.02 -2.97,0.289 -2.2,-1.906 z m -4.26,6.27 c 0,0 -0.81,1.068 -0.18,2.316 0.39,0.98 2.81,0.962 3.55,0.167 C 91.57,3.69 89.06,3.379 89.83,1.183 Z M 86.7,7.638 c 0,0 -1,1.346 -0.49,2.602 0,0.81 2.83,0.96 3.58,0.16 -1.63,0 -3.65,-0.488 -3.09,-2.762 z M 83.62,14.8 c 0,0 -1.4,1.54 -0.15,2.95 1.44,0.8 3.75,0 4.49,-0.75 -1.63,0 -4.9,0.1 -4.34,-2.2 z m -3,5.72 c 0,0 -1.58,1.42 0,3.31 1.43,0.81 4.57,0.2 5.31,-0.59 -1.63,0 -5.99,-1.35 -5.29,-2.72 z m -3.15,6.74 c 0,0 -1.4,1.54 -0.15,2.95 1.44,0.81 6.04,-0.19 6.78,-0.98 -1.63,0 -7.19,0.31 -6.63,-1.97 z"
|
||||
id="path18"
|
||||
transform="translate(0,0.001)" />
|
||||
<path
|
||||
opacity="0.26"
|
||||
d="m 60.33,57.94 c 0,0 6.76,13.59 17.59,13.99 10.84,0.4 10.84,-2.73 10.84,-2.73 0,0 -15.53,3.04 -28.43,-11.26 z m 3.16,7.69 c 2.27,3.1 4.85,5.22 7.72,6.38 0,0 -7.37,11.11 -3.61,20.02 3.75,8.87 13.12,11.07 23.32,21.27 7.94,7.9 12.98,16.6 12.98,16.6 l -4.52,2.4 c 0,0 -9.14,-8.2 -20.73,-7.5 0,0 -2.68,-9.7 -10.58,-17.6 C 56.83,95.95 51.9,81.32 63.49,65.63 Z"
|
||||
id="path22"
|
||||
transform="translate(0,0.001)"
|
||||
sodipodi:nodetypes="csccccsscccsc" />
|
||||
<path
|
||||
opacity="0.27"
|
||||
fill="#ffffff"
|
||||
d="m 71.28,19.39 c 0.99,-0.96 1.14,-0.65 0.85,0.28 -0.98,2.36 0.35,4.65 0.8,6.21 l -3.87,0.11 c 0.11,-2.27 0.25,-4.79 2.22,-6.6 z"
|
||||
id="path26"
|
||||
transform="translate(0,0.001)" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="Simp"
|
||||
style="display:inline">
|
||||
<path
|
||||
fill="#a04d32"
|
||||
stroke="#000000"
|
||||
stroke-width="0.5"
|
||||
d="m 52.84,54.65 c -1.64,-2.19 -2.62,-4.33 -3.21,-6.27 -1.4,-3.3 -3.43,-8.02 -0.61,-17.24 0,0 0.62,-0.38 0,0 -2.62,1.63 -3.57,6.69 -13.08,9.89 -3.21,1.07 -9.87,7.03 -15.43,7.48 C 10.94,49.28 6.393,61.65 -2.091,77.2 l 0.693,6.03 1.4808,7.02 C 7.319,109.3 3.994,101 9.172,110.4 c 2.138,5.4 2.988,4.2 2.988,4.2 -5.641,-23.37 5.43,5.7 5.78,-16.85 1.74,3.65 36.48,-40.52 34.9,-43.1 z"
|
||||
id="path14-3"
|
||||
style="display:inline"
|
||||
sodipodi:nodetypes="cccsssccccccc" />
|
||||
<path
|
||||
fill="#a04d32"
|
||||
stroke="#000000"
|
||||
stroke-width="0.5"
|
||||
d="m 76.29,30.29 c -0.4,-0.45 -0.5,-0.9 -0.4,-1.72 0,0 0.4,-4.11 -16.29,-0.16 -1.07,0.74 2.4,4.73 2.4,4.73 0,0 0.42,0.21 1.05,-0.42 5.7,4.24 17.09,1.64 13.24,-2.43 z"
|
||||
id="path20-6"
|
||||
style="display:inline"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.4 KiB |
@ -1 +0,0 @@
|
||||
kivy[base]
|
Loading…
Reference in New Issue
Block a user