Skip to content

Instantly share code, notes, and snippets.

@livibetter
Last active September 27, 2015 02:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save livibetter/1196740 to your computer and use it in GitHub Desktop.
Save livibetter/1196740 to your computer and use it in GitHub Desktop.
del-patches
From 77e63fcbcd035d4ac321a1914100170172e734bb Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Thu, 8 Sep 2011 18:21:59 +0800
Subject: [PATCH] Add new pos option below_curosr (bcur)
---
README.markdown | 3 ++-
twmnd/twmnd.pro | 2 +-
twmnd/widget.cpp | 25 ++++++++++++++++++++++++-
twmnd/widget.h | 1 +
4 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/README.markdown b/README.markdown
index 57a246b..aa45f95 100644
--- a/README.markdown
+++ b/README.markdown
@@ -44,7 +44,8 @@ height=18 ; In pixel.
; Position of the notification slide.
position=top_right ; Accepted values: top_right (tr), top_left (tl), bottom_right (br),
- ; bottom_left (bl), top_center (tc), bottom_center (bc), center (c).
+ ; bottom_left (bl), top_center (tc), bottom_center (bc), center (c),
+ ; below_cursor (bcur).
; The animation to use when the slide appear
in_animation=38 ; see http://doc.qt.nokia.com/latest/qeasingcurve.html#Type-enum for types
diff --git a/twmnd/twmnd.pro b/twmnd/twmnd.pro
index 4766f53..dc77803 100644
--- a/twmnd/twmnd.pro
+++ b/twmnd/twmnd.pro
@@ -10,7 +10,7 @@ TARGET = twmnd
TEMPLATE = app
CONFIG += release
DESTDIR = ../bin/
-LIBS += `pkg-config --libs-only-l dbus-1`
+LIBS += `pkg-config --libs-only-l dbus-1` -lXfixes
QMAKE_CXXFLAGS += `pkg-config --cflags-only-I dbus-1`
target.path+=/usr/local/bin
diff --git a/twmnd/widget.cpp b/twmnd/widget.cpp
index 4448066..6896c17 100644
--- a/twmnd/widget.cpp
+++ b/twmnd/widget.cpp
@@ -17,6 +17,9 @@
#include <QShortcut>
#include <QIcon>
#include <QWheelEvent>
+#include <QCursor>
+#include <QX11Info>
+#include <X11/extensions/Xfixes.h>
#include "settings.h"
#include "shortcutgrabber.h"
@@ -272,6 +275,18 @@ void Widget::updateCenterAnimation(QVariant value)
show();
}
+void Widget::updateBelowCursorAnimation(QVariant value)
+{
+ const int finalWidth = qobject_cast<QPropertyAnimation*>(m_animation.animationAt(0))->endValue().toInt();
+ const int finalHeight = m_animation.direction() == QAbstractAnimation::Forward ? m_messageQueue.front().data["size"]->toInt() : height();
+ const int h = value.toInt() * finalHeight / finalWidth;
+ const QPoint p = QCursor::pos();
+ const XFixesCursorImage *xcim = XFixesGetCursorImage(QX11Info::display());
+ setGeometry(p.x() - finalWidth / 2, p.y() + xcim->height + 10, value.toInt(), h);
+ layout()->setSpacing(0);
+ show();
+}
+
void Widget::startBounce()
{
QPropertyAnimation* anim = new QPropertyAnimation(this);
@@ -282,7 +297,8 @@ void Widget::startBounce()
QString position = m_messageQueue.front().data["pos"]->toString();
if (position == "top_center" || position == "tc" ||
position == "bottom_center" || position == "bc" ||
- position == "center" || position == "c")
+ position == "center" || position == "c" ||
+ position == "below_cursor" || position == "bcur")
anim->setEndValue(height());
else
anim->setEndValue(40);
@@ -326,6 +342,8 @@ void Widget::updateBounceAnimation(QVariant value)
move(tmpBouncePos.x(), tmpBouncePos.y() - value.toInt());
else if (position == "center" || position == "c")
move(tmpBouncePos.x(), tmpBouncePos.y() - value.toInt());
+ else if (position == "below_cursor" || position == "bcur")
+ move(tmpBouncePos.x(), tmpBouncePos.y() - value.toInt());
layout()->setSpacing(0);
show();
}
@@ -439,6 +457,9 @@ void Widget::connectForPosition(QString position)
else if (position == "center" || position == "c") {
connect(anim, SIGNAL(valueChanged(QVariant)), this, SLOT(updateCenterAnimation(QVariant)));
}
+ else if (position == "below_cursor" || position == "bcur") {
+ connect(anim, SIGNAL(valueChanged(QVariant)), this, SLOT(updateBelowCursorAnimation(QVariant)));
+ }
else {
// top_right seems to be the classic case so fallback to it.
connect(anim, SIGNAL(valueChanged(QVariant)), this, SLOT(updateTopRightAnimation(QVariant)));
@@ -626,6 +647,8 @@ void Widget::updateFinalWidth()
updateBottomCenterAnimation(width);
else if (position == "center" || position == "c")
updateCenterAnimation(width);
+ else if (position == "below_cursor" || position == "bcur")
+ updateBelowCursorAnimation(width);
}
void Widget::onPrevious()
diff --git a/twmnd/widget.h b/twmnd/widget.h
index 2af2430..8a89869 100644
--- a/twmnd/widget.h
+++ b/twmnd/widget.h
@@ -30,6 +30,7 @@ private slots:
void updateTopCenterAnimation(QVariant value);
void updateBottomCenterAnimation(QVariant value);
void updateCenterAnimation(QVariant value);
+ void updateBelowCursorAnimation(QVariant value);
void startBounce();
void unbounce();
void doneBounce();
--
1.7.3.4
--- video_device.c.original 2009-02-02 16:34:08.000000000 +0800
+++ video_device.c 2009-02-02 16:32:10.000000000 +0800
@@ -26,7 +26,7 @@
#include <media/v4l2-ioctl.h>
#endif
-/*#define DEBUG*/
+//#define DEBUG
#define KERNEL_PREFIX "AVLD device: " /* Prefix of each kernel message */
#define VID_DUMMY_DEVICE 0 /* The type of device we create */
@@ -446,14 +446,51 @@
printk(KERNEL_PREFIX "entering v4l_read()\n");
#endif
+ int waiting_time;
+ struct timeval current_time;
// if input size superior to the buffered image size
if (count > BUFFER_SIZE) {
printk(KERNEL_PREFIX "ERROR : you are attempting to read too much data : %d/%lu\n",count,BUFFER_SIZE);
return -EINVAL;
}
- memcpy(buf,image,count*sizeof(char));
-
+ copy_to_user(buf,image,count*sizeof(char));
+
+ // Wait to simulate FPS if necessary
+ #ifdef DEBUG
+ printk(KERNEL_PREFIX "waiting v4l_read() : %d - %ld\n",count,BUFFER_SIZE);
+ #endif
+ if ( fps > 0 ) {
+ do_gettimeofday(&current_time);
+ //printk(KERNEL_PREFIX "t2=%d.%d - t1=%d.%d\n",current_time.tv_sec,current_time.tv_usec,timer.tv_sec,timer.tv_usec);
+
+ // Compute waiting_time
+ waiting_time = HZ/fps - HZ*( (current_time.tv_sec-timer.tv_sec)*USEC_PER_SEC + (current_time.tv_usec-timer.tv_usec) )/USEC_PER_SEC;
+ //waiting_time = MSEC_PER_SEC/fps - ( (current_time.tv_sec-timer.tv_sec)*MSEC_PER_SEC + (current_time.tv_usec-timer.tv_usec)/USEC_PER_MSEC );
+
+ // waits
+ if (waiting_time > 0) {
+ // solution 1
+ interruptible_sleep_on_timeout (&wait,waiting_time);
+
+ // solution 2
+ //set_current_state(TASK_INTERRUPTIBLE);
+ //schedule_timeout(waiting_time);
+
+ // solution 3
+ //msleep_interruptible(waiting_time);
+ }
+
+ do_gettimeofday(&timer);
+ }
+ // Wait reader before continue
+ else if ( fps < 0 ) {
+ #ifdef DEBUG
+ printk (KERN_INFO "fps value : %d\n",fps);
+ #endif
+ mutex_lock_interruptible(&lock);
+ }
+
#ifdef DEBUG
printk(KERNEL_PREFIX "leaving v4l_read() : %d - %ld\n",count,BUFFER_SIZE);
#endif
Index: src/google.py
===================================================================
--- src/google.py (revision 621)
+++ src/google.py (working copy)
@@ -903,6 +903,8 @@
help='Label the machine being used.')
parser.add_option('-n', '--title', dest='title',
help='Title of the item')
+ parser.add_option('--new-title', dest='new_title',
+ help='Blogger only - new title to update a post.')
parser.add_option('--no-convert', dest='convert',
action='store_false', default=True,
help='Google Apps Premier only - do not convert the file' +
Index: src/googlecl/blogger/__init__.py
===================================================================
--- src/googlecl/blogger/__init__.py (revision 621)
+++ src/googlecl/blogger/__init__.py (working copy)
@@ -70,9 +70,8 @@
entry_list = client.UploadPosts(content_list,
blog_title=options.blog,
post_title=options.title,
- is_draft=_map_access_string(options.access))
- if options.tags:
- client.LabelPosts(entry_list, options.tags)
+ is_draft=_map_access_string(options.access),
+ tags=options.tags)
def _run_delete(client, options, args):
@@ -82,6 +81,14 @@
client.DeleteEntryList(post_entries, 'post', options.prompt)
+def _run_update(client, options, args):
+ content = ' '.join(options.src + args)
+ entry = client.UpdatePost(blog_title=options.blog, post_title=options.title,
+ post_new_title=options.new_title, content=content,
+ is_draft=_map_access_string(options.access),
+ tags=options.tags)
+
+
def _run_list(client, options, args):
titles_list = googlecl.build_titles_list(options.title, args)
entries = client.GetPosts(options.blog, titles_list,
@@ -104,6 +111,10 @@
'post': googlecl.base.Task('Post content.', callback=_run_post,
required=['src', 'blog'],
optional=['title', 'tags', 'access']),
+ 'update': googlecl.base.Task('Update a post', callback=_run_update,
+ required=['blog', 'title'],
+ optional=['src', 'new-title', 'tags',
+ 'access']),
'list': googlecl.base.Task('List posts in a blog',
callback=_run_list,
required=['fields', 'blog', 'delimiter'],
Index: src/googlecl/blogger/service.py
===================================================================
--- src/googlecl/blogger/service.py (revision 621)
+++ src/googlecl/blogger/service.py (working copy)
@@ -25,6 +25,7 @@
import gdata.blogger.service
import logging
import os
+import sys
from googlecl import safe_encode
import googlecl.base
import googlecl.service
@@ -48,7 +49,8 @@
gdata.blogger.service.BloggerService.__init__(self, account_type='GOOGLE')
googlecl.service.BaseServiceCL.__init__(self, SECTION_HEADER, config)
- def _upload_content(self, post_title, content, blog_id=None, is_draft=False):
+ def _upload_content(self, post_title, content, blog_id=None, is_draft=False,
+ tags=None):
"""Uploads content.
Keyword arguments:
@@ -57,6 +59,7 @@
content: String to get posted. This may be contents from a file, but NOT
the path itself!
is_draft: If this content is a draft post or not. (Default False)
+ tags: String representation of tags in a comma separated list.
Returns:
Entry of post. (Returns same results as self.AddPost())
@@ -68,6 +71,8 @@
control = atom.Control()
control.draft = atom.Draft(text='yes')
entry.control = control
+ if tags:
+ entry = self.LabelPosts([entry], tags, do_update=False)[0]
return self.AddPost(entry, blog_id)
def _get_blog_id(self, blog_title=None, user_id='default'):
@@ -120,7 +125,7 @@
GetPosts = get_posts
- def label_posts(self, post_entries, tags):
+ def label_posts(self, post_entries, tags, do_update=True):
"""Add or remove labels on a list of posts.
Keyword arguments:
@@ -148,15 +153,73 @@
if add_set:
new_tags = [atom.Category(term=tag, scheme=scheme) for tag in add_set]
post.category.extend(new_tags)
- updated_post = self.UpdatePost(post)
- if updated_post:
- successes.append(updated_post)
+ if do_update:
+ updated_post = self.UpdatePost(post)
+ if updated_post:
+ successes.append(updated_post)
+ else:
+ successes.append(post)
return successes
LabelPosts = label_posts
+ def update_post(self, entry=None, blog_title=None, post_title=None,
+ post_new_title=None, content=None, is_draft=None, tags=None):
+ """Update a post.
+
+ Keyword arguments:
+ entry: The post to be updated. If it's None, then use post_title to
+ search.
+ blog_title: Name of the blog to update.
+ post_title: Name of the post to search.
+ post_new_title: New title of the post. Set None if do not want to update.
+ content: String to update old content. This may be contents from a
+ file, but NOT the path itself! Set None if do not want to
+ update.
+ is_draft: Draft status to update the entry. Set None if do not want to
+ update.
+ tags: tags to update the entry using label_posts method. Set None if do
+ not want to update.
+
+ Returns:
+ Updated post entry.
+ """
+ max_size = 500000
+ if not entry:
+ posts = self.GetPosts(blog_title=blog_title, post_titles=post_title)
+ entry = self.GetSingleEntry(posts)
+ if not entry:
+ LOG.error('Failed to find the post.')
+ return
+
+ if post_new_title is not None:
+ entry.title = atom.Title(title_type='xhtml', text=post_new_title)
+
+ if content:
+ if os.path.exists(content):
+ with open(content, 'r') as content_file:
+ content = content_file.read(max_size)
+ if content_file.read(1):
+ LOG.warning('Only read first ' + str(max_size) +
+ ' bytes of file ' + content_string)
+ entry.content = atom.Content(content_type='html', text=content)
+
+ control = atom.Control()
+ control.draft = atom.Draft(text=['no', 'yes'][is_draft or 0])
+ entry.control = control
+ try:
+ if tags:
+ entry = self.LabelPosts([entry], tags, do_update=False)[0]
+ self.Put(entry, entry.GetEditLink().href)
+ LOG.info('Post updated: %s', entry.GetHtmlLink().href)
+ except self.request_error, err:
+ LOG.error(safe_encode('Failed to update: ' + unicode(err)))
+ return entry
+
+ UpdatePost = update_post
+
def upload_posts(self, content_list, blog_title=None, post_title=None,
- is_draft=False):
+ is_draft=False, tags=None):
"""Uploads posts.
Args:
@@ -165,6 +228,7 @@
post_title: Name to give the post(s).
is_draft: Set True to upload as private draft(s), False to make upload(s)
public.
+ tags: String representation of tags in a comma separated list.
Returns:
List of entries of successful posts.
@@ -191,7 +255,8 @@
entry = self._upload_content(post_title or title,
content,
blog_id=blog_id,
- is_draft=is_draft)
+ is_draft=is_draft,
+ tags=tags)
except self.request_error, err:
LOG.error(safe_encode('Failed to post: ' + unicode(err)))
else:
Index: test_suite/test_blogger.sh
===================================================================
--- test_suite/test_blogger.sh (revision 621)
+++ test_suite/test_blogger.sh (working copy)
@@ -32,6 +32,7 @@
post_title="example post title"
+post_new_title="example new post title"
post_body="example post body"
post_tags="a,b"
@@ -45,7 +46,7 @@
function check_posts_number {
should_be \
- "python google.py blogger list --title \"$post_title\" --blog $blogname -u $auth_username" \
+ "python google.py blogger list --title \"${2:-$post_title}\" --blog $blogname -u $auth_username" \
$1 \
0 \
"blog post" \
@@ -70,21 +71,27 @@
if [[ $auth_executed == "0" ]]; then
auth_executed=1
- python google.py blogger list --blog $blogname --force-auth -u $auth_username
+ python google.py blogger list --blog "$blogname" --force-auth -u $auth_username
fi
check_posts_number 0
# Creating new blog post.
- python google.py blogger post --title "$post_title" --blog $blogname -u $auth_username "adlasdasd"
+ python google.py blogger post --title "$post_title" --blog "$blogname" -u $auth_username "adlasdasd"
check_posts_number 1
# Tagging the blog post, unfortunately there is no way to check if it worked.
- python google.py blogger tag --blog $blogname --title "$post_title" -u $auth_username --tags "$post_tags"
+ python google.py blogger tag --blog "$blogname" --title "$post_title" -u $auth_username --tags "$post_tags"
+ # Updating the blog post's title, unfortunately there is no way to check if content is updated.
+ python google.py blogger update --blog "$blogname" --title "$post_title" -u $auth_username --new_title "$post_new_title" "blah new content"
+
+ # check new updated post title
+ check_posts_number 1 "$post_new_title"
+
# Deleting the blog post.
- python google.py blogger delete --blog $blogname --title "$post_title" -u $auth_username --yes
+ python google.py blogger delete --blog "$blogname" --title "$post_new_title" -u $auth_username --yes
check_posts_number 0
Index: man/google.1
===================================================================
--- man/google.1 (revision 621)
+++ man/google.1 (working copy)
@@ -59,7 +59,7 @@
.IP
Requires: (title OR query) Optional: photo
.PP
-Available tasks for service blogger: 'post', 'tag', 'list', 'delete'
+Available tasks for service blogger: 'post', 'tag', 'list', 'update', 'delete'
.IP
post: Post content.
.IP
@@ -73,6 +73,10 @@
.IP
Requires: fields AND blog AND delimiter Optional: title, owner
.IP
+update: Update a post.
+.IP
+Requires: blog AND title Optional: src, new\-title, tags, access
+.IP
delete: Delete a post.
.IP
Requires: blog AND title
From a69b0fb091e1000c2e35fb72f344914941177f40 Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Sat, 23 Jul 2011 15:33:51 +0800
Subject: [PATCH 1/3] Make footnote to display other return symbol
<https://github.com/trentm/python-markdown2/issues/37>
---
lib/markdown2.py | 5 ++++-
test/tm-cases/footnotes_return_symbol.html | 27 +++++++++++++++++++++++++++
test/tm-cases/footnotes_return_symbol.opts | 1 +
test/tm-cases/footnotes_return_symbol.tags | 1 +
test/tm-cases/footnotes_return_symbol.text | 18 ++++++++++++++++++
5 files changed, 51 insertions(+), 1 deletions(-)
create mode 100644 test/tm-cases/footnotes_return_symbol.html
create mode 100644 test/tm-cases/footnotes_return_symbol.opts
create mode 100644 test/tm-cases/footnotes_return_symbol.tags
create mode 100644 test/tm-cases/footnotes_return_symbol.text
diff --git a/lib/markdown2.py b/lib/markdown2.py
index 87e5123..1cfb761 100755
--- a/lib/markdown2.py
+++ b/lib/markdown2.py
@@ -1650,6 +1650,9 @@ class Markdown(object):
return "\n\n".join(grafs)
def _add_footnotes(self, text):
+ # Currently the argument of footnote is backlink_innerhtml
+ backlink_innerhtml = self.extras['footnotes'] if self.extras['footnotes'] else '&#8617;';
+
if self.footnotes:
footer = [
'<div class="footnotes">',
@@ -1664,7 +1667,7 @@ class Markdown(object):
backlink = ('<a href="#fnref-%s" '
'class="footnoteBackLink" '
'title="Jump back to footnote %d in the text.">'
- '&#8617;</a>' % (id, i+1))
+ '%s</a>' % (id, i+1, backlink_innerhtml))
if footer[-1].endswith("</p>"):
footer[-1] = footer[-1][:-len("</p>")] \
+ '&nbsp;' + backlink + "</p>"
diff --git a/test/tm-cases/footnotes_return_symbol.html b/test/tm-cases/footnotes_return_symbol.html
new file mode 100644
index 0000000..0d0c638
--- /dev/null
+++ b/test/tm-cases/footnotes_return_symbol.html
@@ -0,0 +1,27 @@
+<p>This is a para with a footnote.<sup class="footnote-ref" id="fnref-1"><a href="#fn-1">1</a></sup></p>
+
+<p>This is another para with a footnote<sup class="footnote-ref" id="fnref-2"><a href="#fn-2">2</a></sup> in it. Actually it has two<sup class="footnote-ref" id="fnref-3"><a href="#fn-3">3</a></sup> of
+them. No, three<sup class="footnote-ref" id="fnref-4"><a href="#fn-4">4</a></sup>.</p>
+
+<div class="footnotes">
+<hr />
+<ol>
+<li id="fn-1">
+<p>Here is the body of the first footnote.&nbsp;<a href="#fnref-1" class="footnoteBackLink" title="Jump back to footnote 1 in the text.">^</a></p>
+</li>
+
+<li id="fn-2">
+<p>And of the second footnote.</p>
+
+<p>This one has multiple paragraphs.&nbsp;<a href="#fnref-2" class="footnoteBackLink" title="Jump back to footnote 2 in the text.">^</a></p>
+</li>
+
+<li id="fn-3">
+<p>Here is a footnote body that starts on next line.&nbsp;<a href="#fnref-3" class="footnoteBackLink" title="Jump back to footnote 3 in the text.">^</a></p>
+</li>
+
+<li id="fn-4">
+<p>quickie "that looks like a link ref if not careful"&nbsp;<a href="#fnref-4" class="footnoteBackLink" title="Jump back to footnote 4 in the text.">^</a></p>
+</li>
+</ol>
+</div>
diff --git a/test/tm-cases/footnotes_return_symbol.opts b/test/tm-cases/footnotes_return_symbol.opts
new file mode 100644
index 0000000..8220e00
--- /dev/null
+++ b/test/tm-cases/footnotes_return_symbol.opts
@@ -0,0 +1 @@
+{"extras": {"footnotes": "^"}}
diff --git a/test/tm-cases/footnotes_return_symbol.tags b/test/tm-cases/footnotes_return_symbol.tags
new file mode 100644
index 0000000..9e26e29
--- /dev/null
+++ b/test/tm-cases/footnotes_return_symbol.tags
@@ -0,0 +1 @@
+footnotes
diff --git a/test/tm-cases/footnotes_return_symbol.text b/test/tm-cases/footnotes_return_symbol.text
new file mode 100644
index 0000000..7d6e716
--- /dev/null
+++ b/test/tm-cases/footnotes_return_symbol.text
@@ -0,0 +1,18 @@
+This is a para with a footnote.[^1]
+
+This is another para with a footnote[^2] in it. Actually it has two[^3] of
+them. No, three[^4].
+
+
+[^1]: Here is the body of the first footnote.
+
+[^2]: And of the second footnote.
+
+ This one has multiple paragraphs.
+
+[^3]:
+ Here is a footnote body that starts on next line.
+
+[^4]: quickie "that looks like a link ref if not careful"
+
+
--
1.7.3.4
From 3a913a6fb9748a7c1c71ea2ac9497d195460790d Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Thu, 28 Jul 2011 18:27:57 +0800
Subject: [PATCH 2/3] Make gen_perf_cases.py runnable
trentm#63
---
perf/gen_perf_cases.py | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/perf/gen_perf_cases.py b/perf/gen_perf_cases.py
index ecd4c54..5a5a841 100755
--- a/perf/gen_perf_cases.py
+++ b/perf/gen_perf_cases.py
@@ -20,7 +20,12 @@ def gen_aspn_cases(limit=0):
return
os.makedirs(base_dir)
sys.stdout.write("generate %s" % base_dir); sys.stdout.flush()
- recipes_path = expanduser("~/as/code.as.com/db/aspn/recipes.pprint")
+ for recipes_path in (expanduser("~/as/code.as.com/db/aspn/recipes.pprint"), 'recipes.pprint'):
+ if exists(recipes_path):
+ break
+ else:
+ print >>sys.stderr, 'Can not find recipes.pprint'
+ sys.exit(1)
recipe_dicts = eval(open(recipes_path).read())
for i, r in enumerate(recipe_dicts):
sys.stdout.write('.'); sys.stdout.flush()
@@ -28,8 +33,7 @@ def gen_aspn_cases(limit=0):
f.write(r["desc"])
f.close()
- for j, c in enumerate(sorted(r["comments"],
- key=operator.itemgetter("pub_date"))):
+ for j, c in enumerate(sorted(r["comments"])):
text = _markdown_from_aspn_html(c["comment"])
headline = c["title"].strip()
if headline:
--
1.7.3.4
From 5b342bdecbfa38cc7582407fd6659bcefa21fc4e Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Sat, 13 Aug 2011 19:48:39 +0800
Subject: [PATCH 3/3] Fix, refactor, clean up perf/*, and make output more clear. (trentm#63)
---
perf/gen_perf_cases.py | 24 +++++---
perf/perf.py | 147 +++++++++++++++++++++++++--------------------
perf/time_markdown_pl.pl | 4 +
perf/util.py | 10 +---
4 files changed, 103 insertions(+), 82 deletions(-)
diff --git a/perf/gen_perf_cases.py b/perf/gen_perf_cases.py
index ecd4c54..619335a 100755
--- a/perf/gen_perf_cases.py
+++ b/perf/gen_perf_cases.py
@@ -1,26 +1,32 @@
-#!/usr/bin/env python2.5
+#!/usr/bin/env python
import os
from os.path import *
import sys
import re
-import datetime
from glob import glob
-import operator
import shutil
import codecs
+SEARCH_PATH = [expanduser("~/as/code.as.com/db/aspn"), '.']
TMP = "tmp-"
def gen_aspn_cases(limit=0):
base_dir = TMP+'aspn-cases'
if exists(base_dir):
- print "'%s' exists, skipping" % base_dir
+ print "'%s' exists, skipping. If you want to regenerate, please manually delete it." % base_dir
return
os.makedirs(base_dir)
sys.stdout.write("generate %s" % base_dir); sys.stdout.flush()
- recipes_path = expanduser("~/as/code.as.com/db/aspn/recipes.pprint")
+ for recipes_path in SEARCH_PATH:
+ recipes_path = join(recipes_path, 'recipes.pprint')
+ if exists(recipes_path):
+ break
+ else:
+ print
+ print >>sys.stderr, 'Can not find recipes.pprint, please specify a path where can find the file.'
+ sys.exit(1)
recipe_dicts = eval(open(recipes_path).read())
for i, r in enumerate(recipe_dicts):
sys.stdout.write('.'); sys.stdout.flush()
@@ -28,8 +34,7 @@ def gen_aspn_cases(limit=0):
f.write(r["desc"])
f.close()
- for j, c in enumerate(sorted(r["comments"],
- key=operator.itemgetter("pub_date"))):
+ for j, c in enumerate(sorted(r["comments"])):
text = _markdown_from_aspn_html(c["comment"])
headline = c["title"].strip()
if headline:
@@ -49,7 +54,7 @@ def gen_aspn_cases(limit=0):
def gen_test_cases():
base_dir = TMP+"test-cases"
if exists(base_dir):
- print "'%s' exists, skipping" % base_dir
+ print "'%s' exists, skipping. If you want to regenerate, please manually delete it." % base_dir
return
os.makedirs(base_dir)
print "generate %s" % base_dir
@@ -273,6 +278,9 @@ if __name__ == "__main__":
limit = int(sys.argv[1])
except:
limit = 0
+ for i in range(1, len(sys.argv)):
+ # put them all in, it doesn't matter what they are.
+ SEARCH_PATH += sys.argv[i]
gen_aspn_cases(limit)
gen_test_cases()
diff --git a/perf/perf.py b/perf/perf.py
index ea6f10e..99a7d5d 100755
--- a/perf/perf.py
+++ b/perf/perf.py
@@ -10,10 +10,10 @@ Example:
import os
import sys
-import timeit
import time
from os.path import *
from glob import glob
+from StringIO import StringIO
import optparse
from util import hotshotit
@@ -22,69 +22,87 @@ from util import hotshotit
clock = sys.platform == "win32" and time.clock or time.time
-@hotshotit
-def hotshot_markdown_py(cases_dir, repeat):
- time_markdown_py(cases_dir, repeat)
-
-def time_markdown_py(cases_dir, repeat):
+def init_markdown():
sys.path.insert(0, join("..", "test"))
import markdown
del sys.path[0]
- markdowner = markdown.Markdown()
- times = []
- for i in range(repeat):
- start = clock()
- for path in glob(join(cases_dir, "*.text")):
- f = open(path, 'r')
- content = f.read()
- f.close()
- try:
- markdowner.convert(content)
- markdowner.reset()
- except UnicodeError:
- pass
- end = clock()
- times.append(end - start)
- print " markdown.py: best of %d: %.3fs" % (repeat, min(times))
+ return markdown.Markdown()
-@hotshotit
-def hotshot_markdown2_py(cases_dir, repeat):
- time_markdown2_py(cases_dir, repeat)
-
-def time_markdown2_py(cases_dir, repeat):
+def init_markdown2():
sys.path.insert(0, "../lib")
import markdown2
del sys.path[0]
- markdowner = markdown2.Markdown()
- times = []
- for i in range(repeat):
- start = clock()
- for path in glob(join(cases_dir, "*.text")):
- f = open(path, 'r')
- content = f.read()
- f.close()
+ return markdown2.Markdown()
+
+def run_py_markdown(mkd, markdowner, cases_dir):
+ global show_progress
+ for path in glob(join(cases_dir, "*.text")):
+ f = open(path, 'r')
+ content = f.read()
+ f.close()
+ try:
+ # Mute markdowner
+ sys.stdout = StringIO()
markdowner.convert(content)
- end = clock()
- times.append(end - start)
- print " markdown2.py: best of %d: %.3fs" % (repeat, min(times))
+ if show_progress:
+ sys.__stdout__.write('.')
+ except Exception:
+ # Don't print out traceback, this is profiling, not unit testing.
+ sys.__stdout__.write('E')
+ finally:
+ # Release normally
+ sys.stdout.close()
+ sys.stdout = sys.__stdout__
+ if mkd == 'markdown.py':
+ markdowner.reset()
+ sys.stdout.flush()
+
+def run_pl_markdown(mkd, markdowner, cases_dir):
+ global show_progress
+ cmd = 'perl time_markdown_pl.pl "%s"'
+ if not show_progress:
+ cmd += ' mute'
+ os.system(cmd % cases_dir)
+
+
+MKD = {
+ 'markdown.py': {
+ 'init': init_markdown,
+ 'run': run_py_markdown,
+ },
+ 'markdown2.py': {
+ 'init': init_markdown2,
+ 'run': run_py_markdown,
+ },
+ 'Markdown.pl': {
+ 'init': lambda: None,
+ 'run': run_pl_markdown,
+ },
+ }
+MKDS = MKD.keys()
+
-def time_markdown_pl(cases_dir, repeat):
+@hotshotit
+def hotshot_py_markdown(mkd, cases_dir, repeat):
+ time_markdown(mkd, cases_dir, repeat)
+
+def time_markdown(mkd, cases_dir, repeat):
+ markdowner = MKD[mkd]['init']()
times = []
for i in range(repeat):
+ print '#%2d: ' % (i + 1),
+ sys.stdout.flush()
start = clock()
- os.system('perl time_markdown_pl.pl "%s"' % cases_dir)
+ MKD[mkd]['run'](mkd, markdowner, cases_dir)
end = clock()
+ print
times.append(end - start)
- print " Markdown.pl: best of %d: %.3fs" % (repeat, min(times))
+ print "%s: best of %d: %.3fs" % (mkd, repeat, min(times))
+ print
def time_all(cases_dir, repeat):
- time_markdown_pl(cases_dir, repeat=repeat)
- time_markdown_py(cases_dir, repeat=repeat)
- time_markdown2_py(cases_dir, repeat=repeat)
-
-def time_not_markdown_py(cases_dir, repeat):
- time_markdown_pl(cases_dir, repeat=repeat)
- time_markdown2_py(cases_dir, repeat=repeat)
+ for mkd in MKDS:
+ time_markdown(mkd, cases_dir, repeat=repeat)
#---- mainline
@@ -95,6 +113,7 @@ class _NoReflowFormatter(optparse.IndentedHelpFormatter):
return description or ""
def main(args=sys.argv):
+ global show_progress
usage = "python perf.py [-i all|markdown.py|markdown2.py|Markdown.pl] [cases-dir]"
parser = optparse.OptionParser(prog="perf", usage=usage,
description=__doc__, formatter=_NoReflowFormatter())
@@ -104,10 +123,13 @@ def main(args=sys.argv):
parser.add_option("-i", "--implementation",
help="Markdown implementation(s) to run: all (default), "
"markdown.py, markdown2.py, Markdown.pl, not-markdown.py")
- parser.add_option("--hotshot", "--profile", dest="hotshot",
+ parser.add_option("-H", "--hotshot", dest="hotshot",
action="store_true",
help="profile and dump stats about a single run (not supported "
"for Markdown.pl)")
+ parser.add_option("-p", "--progress", dest="progress",
+ action="store_true", default=False,
+ help="Show the progress")
parser.set_defaults(implementation="all", hotshot=False, repeat=None)
opts, args = parser.parse_args()
@@ -123,31 +145,26 @@ def main(args=sys.argv):
if opts.repeat is None:
opts.repeat = opts.hotshot and 1 or 3
+ show_progress = opts.progress
if opts.hotshot:
assert opts.implementation in ("markdown.py", "markdown2.py")
- timer_name = "hotshot_%s" \
- % opts.implementation.lower().replace('.', '_').replace('-', '_')
- d = sys.modules[__name__].__dict__
- if timer_name not in d:
- raise ValueError("no '%s' timer function" % timer_name)
- timer = d[timer_name]
print "Profile conversion of %s (plat=%s):" \
% (os.path.join(cases_dir, "*.text"), sys.platform)
- timer(cases_dir, repeat=opts.repeat)
+ mkd = opts.implementation
+ hotshot_py_markdown(mkd, cases_dir, repeat=opts.repeat)
print
- os.system("python show_stats.py %s.prof" % timer_name)
+ os.system("python show_stats.py hotshot_%s.prof" % mkd)
else:
- timer_name = "time_%s" \
- % opts.implementation.lower().replace('.', '_').replace('-', '_')
-
- d = sys.modules[__name__].__dict__
- if timer_name not in d:
- raise ValueError("no '%s' timer function" % timer_name)
- timer = d[timer_name]
+ mkd = opts.implementation
+ if mkd not in MKDS and mkd != 'all':
+ raise ValueError("no such '%s' Markdown implementation" % mkd)
print "Time conversion of %s (plat=%s):" \
% (os.path.join(cases_dir, "*.text"), sys.platform)
- timer(cases_dir, repeat=opts.repeat)
+ if mkd == 'all':
+ time_all(cases_dir, repeat=opts.repeat)
+ else:
+ time_markdown(mkd, cases_dir, repeat=opts.repeat)
if __name__ == "__main__":
sys.exit( main(sys.argv) )
diff --git a/perf/time_markdown_pl.pl b/perf/time_markdown_pl.pl
index eed1110..7a2699d 100755
--- a/perf/time_markdown_pl.pl
+++ b/perf/time_markdown_pl.pl
@@ -3,9 +3,13 @@ use Markdown;
my @text_files = <$ARGV[0]/*.text>;
my $file, $content;
+$| = 1;
for $file (@text_files) {
local(*INPUT, $/);
open (INPUT, $file) || die "can't open $file: $!";
$content = <INPUT>;
Markdown::Markdown($content);
+ if ($ARGV[1] ne "mute") {
+ print ".";
+ }
}
diff --git a/perf/util.py b/perf/util.py
index 05a22a0..0b40489 100644
--- a/perf/util.py
+++ b/perf/util.py
@@ -3,15 +3,7 @@
"""Perf utility functions"""
-import os
-from os.path import basename
import sys
-import md5
-import re
-import stat
-import textwrap
-import types
-from pprint import pprint, pformat
# Global dict for holding specific hotshot profilers
@@ -45,7 +37,7 @@ def hotshotit(func):
def wrapper(*args, **kw):
import hotshot
global hotshotProfilers
- prof_name = func.func_name+".prof"
+ prof_name = "hotshot_%s.prof" % args[0]
profiler = hotshotProfilers.get(prof_name)
if profiler is None:
profiler = hotshot.Profile(prof_name)
--
1.7.3.4
From ee9e90cd2320b4dea0afaac6aadb98c6be76fd7b Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Wed, 27 Jul 2011 08:09:39 +0800
Subject: [PATCH 1/3] Add predefined styles for LineBox
---
linebox.py | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++
urwid/graphics.py | 91 ++++++++++++++++---
2 files changed, 336 insertions(+), 14 deletions(-)
create mode 100755 linebox.py
diff --git a/linebox.py b/linebox.py
new file mode 100755
index 0000000..e41339a
--- /dev/null
+++ b/linebox.py
@@ -0,0 +1,259 @@
+#!/usr/bin/env python
+#
+# Urwid LineBox example program
+# Copyright (C) 2011 Yu-Jie Lin
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Urwid web site: http://excess.org/urwid/
+
+"""
+Urwid example demonstrating use of the LineBox widget.
+"""
+
+import urwid
+
+
+class LineBoxDemo:
+
+ LBOX_ATTRS = {
+ 'inset': {
+ 'tline': 'line dark',
+ 'lline': 'line dark',
+ 'tlcorner': 'line dark',
+ 'blcorner': 'line dark',
+ 'rline': 'line bright',
+ 'bline': 'line bright',
+ 'trcorner': 'line bright',
+ 'brcorner': 'line bright',
+ },
+ 'outset': {
+ 'tline': 'line bright',
+ 'lline': 'line bright',
+ 'tlcorner': 'line bright',
+ 'blcorner': 'line bright',
+ 'rline': 'line dark',
+ 'bline': 'line dark',
+ 'trcorner': 'line dark',
+ 'brcorner': 'line dark',
+ },
+ 'grooved/ridged': {
+ 'tline': 'line bright/dark',
+ 'lline': 'line bright/dark',
+ 'tlcorner': 'line bright/dark',
+ 'blcorner': 'line bright/dark',
+ 'rline': 'line dark/bright',
+ 'bline': 'line dark/bright',
+ 'trcorner': 'line dark/bright',
+ 'brcorner': 'line dark/bright',
+ },
+ 'ridged/grooved': {
+ 'tline': 'line dark/bright',
+ 'lline': 'line dark/bright',
+ 'tlcorner': 'line dark/bright',
+ 'blcorner': 'line dark/bright',
+ 'rline': 'line bright/dark',
+ 'bline': 'line bright/dark',
+ 'trcorner': 'line bright/dark',
+ 'brcorner': 'line bright/dark',
+ },
+ 'raised/lowered': {
+ 'tline': 'line bright/dark',
+ 'lline': 'line bright/dark',
+ 'tlcorner': 'line bright/dark',
+ 'blcorner': 'line bright/dark',
+ 'rline': 'line bright/dark',
+ 'bline': 'line bright/dark',
+ 'trcorner': 'line bright/dark',
+ 'brcorner': 'line bright/dark',
+ },
+ 'lowered/raised': {
+ 'tline': 'line dark/bright',
+ 'lline': 'line dark/bright',
+ 'tlcorner': 'line dark/bright',
+ 'blcorner': 'line dark/bright',
+ 'rline': 'line dark/bright',
+ 'bline': 'line dark/bright',
+ 'trcorner': 'line dark/bright',
+ 'brcorner': 'line dark/bright',
+ },
+ 'rainbow': {
+ 'tline': 'line black',
+ 'bline': 'line red',
+ 'lline': 'line green',
+ 'rline': 'line brown',
+ 'tlcorner': 'line blue',
+ 'trcorner': 'line magenta',
+ 'blcorner': 'line cyan',
+ 'brcorner': 'line yellow',
+ },
+ 'default': {},
+ }
+
+ def __init__(self):
+
+ is_utf8 = urwid.get_encoding_mode() == 'utf8'
+
+ self.custom_style_chars = u'abcdefgh'
+ self.lbox_attr = 'default'
+
+ self.style = 'single'
+ self.style_chars = None
+ lbox = self.create_lbox()
+ self.lbox = lbox
+ self.style_chars = self.lbox.style_chars
+
+ style_name_width = max(len(name) for name in urwid.LineBox.STYLES.keys())
+ style_rows = [('flow', urwid.Text('Styles:'))]
+ style_buttons = []
+ styles = urwid.LineBox.STYLES.keys()
+ styles.sort()
+ for style in styles:
+ try:
+ if not is_utf8:
+ (urwid.LineBox.STYLES[style] or u'').encode('ascii')
+ except UnicodeEncodeError:
+ text = ' %%-%ds (UTF-8 mode required)' % style_name_width
+ row = urwid.Text(text % style)
+ row = urwid.AttrMap(row, 'option disable')
+ style_rows.append(row)
+ continue
+
+ rb = urwid.RadioButton(style_buttons, style, state=style=='single')
+ if style != 'custom':
+ rb_style_chars = urwid.Text(urwid.LineBox.STYLES[style])
+ else:
+ rb_style_chars = urwid.Edit('', self.custom_style_chars)
+ urwid.connect_signal(rb_style_chars, 'change',
+ self.change_style_chars)
+ rb_style_chars = urwid.Padding(
+ urwid.AttrMap(
+ rb_style_chars, 'custom style', 'custom style focus'),
+ width=8)
+
+ urwid.connect_signal(rb, 'change', self.change_style)
+
+ row = urwid.Columns([
+ ('fixed', style_name_width + 4, rb),
+ rb_style_chars,
+ ], dividechars=1)
+
+ row = urwid.AttrMap(row, 'option', 'option focus')
+ style_rows.append(row)
+ self.style_buttons = style_buttons
+ style_box = urwid.Pile(style_rows)
+
+ attr_rows = [('flow', urwid.Text('Attributes:'))]
+ attr_buttons = []
+ attrs = self.LBOX_ATTRS.keys()
+ attrs.sort()
+ for name in attrs:
+ rb = urwid.RadioButton(attr_buttons, name)
+ urwid.connect_signal(rb, 'change', self.change_attr)
+ row = urwid.AttrMap(rb, 'option', 'option focus')
+ attr_rows.append(row)
+ self.attr_buttons = attr_buttons
+ attr_box = urwid.Pile(attr_rows)
+
+ style_attr_boxes = urwid.Columns([style_box, attr_box], dividechars=1)
+ header = urwid.Text('Urwid LineBox example program - F8 exits.')
+ header = urwid.AttrMap(header, 'title')
+
+ body = urwid.Pile([
+ ('flow', lbox),
+ ('flow', urwid.Divider()),
+ urwid.Filler(style_attr_boxes, valign='top'),
+ ])
+ body = urwid.AttrMap(body, 'normal')
+ frame = urwid.Frame(body, header=header)
+ self.frame = frame
+ palette = [
+ ('normal', 'black', 'white'),
+ ('title', 'white', 'dark red'),
+ ('option', 'white', 'dark blue'),
+ ('option disable', 'dark gray', 'dark blue'),
+ ('option focus', 'white', 'dark green'),
+ ('custom style', 'white', 'dark red'),
+ ('custom style focus', 'light blue', 'dark red'),
+ ('line bright', '', '', '', 'g80', 'white'),
+ ('line dark', '', '', '', 'g40', 'white'),
+ ('line bright/dark', '', '', '', 'g80', 'g40'),
+ ('line dark/bright', '', '', '', 'g40', 'g80'),
+ ('line black', 'black', 'white'),
+ ('line red', 'dark red', 'white'),
+ ('line green', 'dark green', 'white'),
+ ('line brown', 'brown', 'white'),
+ ('line blue', 'dark blue', 'white'),
+ ('line magenta', 'dark magenta', 'white'),
+ ('line cyan', 'dark cyan', 'white'),
+ ('line yellow', 'yellow', 'white'),
+ ]
+
+ loop = urwid.MainLoop(frame, unhandled_input=self.unhandled_input)
+ loop.screen.set_terminal_properties(colors=256)
+ loop.screen.reset_default_terminal_palette()
+ loop.screen.register_palette(palette)
+ self.loop = loop
+
+ def create_lbox(self):
+
+ text = urwid.Text('Inside the LineBox')
+ return urwid.LineBox(text, 'LineBox Title',
+ style=self.style, style_chars=self.style_chars,
+ **self.LBOX_ATTRS[self.lbox_attr])
+
+ def change_attr(self, w, state):
+
+ if state:
+ self.lbox_attr = w.label
+ self.lbox = self.create_lbox()
+ self.frame.body.base_widget.widget_list[0] = self.lbox
+
+ def change_style(self, w, state):
+
+ if state:
+ if w.label != 'custom':
+ self.lbox.set_style(w.label,
+ **self.LBOX_ATTRS[self.lbox_attr])
+ else:
+ style_chars = self.custom_style_chars[:8]
+ style_chars += '?'*(8 - len(style_chars))
+ self.lbox.set_style(w.label, style_chars,
+ **self.LBOX_ATTRS[self.lbox_attr])
+ self.style = self.lbox.style
+ self.style_chars = self.lbox.style_chars
+
+ def change_style_chars(self, w, text):
+
+ self.custom_style_chars = text
+ for rbtn in self.style_buttons:
+ if rbtn.label == 'custom':
+ rbtn.set_state(True, do_callback=False)
+ self.change_style(rbtn, True)
+ return
+
+ def run(self):
+
+ self.loop.run()
+
+ def unhandled_input(self, key):
+
+ if key == 'f8':
+ raise urwid.ExitMainLoop
+
+
+if __name__ == '__main__':
+ demo = LineBoxDemo()
+ demo.run()
diff --git a/urwid/graphics.py b/urwid/graphics.py
index 092045c..e13ad8f 100755
--- a/urwid/graphics.py
+++ b/urwid/graphics.py
@@ -92,6 +92,7 @@ class BigText(FixedWidget):
class LineBox(WidgetDecoration, WidgetWrap):
+ # Unused after adding predefined styles
ACS_HLINE = u'─'
ACS_VLINE = u'│'
@@ -100,17 +101,56 @@ class LineBox(WidgetDecoration, WidgetWrap):
ACS_LLCORNER = u'└'
ACS_LRCORNER = u'┘'
+ STYLES = { # tblrttbb
+ # lrlr
+ 'ascii' : u'--||++++', # default for non-UTF-8
+ 'ascii-double' : u'==||++++', # default for non-UTF-8
+ 'ascii-slash' :ur'--||/\\/',
+ 'ascii-wave' : u'~~||~~~~',
+ 'ascii-dots' : u'........',
+ 'ascii-asterisks' : u'********',
+ 'ascii-millionaire': u'$$$$$$$$',
+ 'single' : u'──││┌┐└┘', # default for UTF-8
+ 'single-d-1' : u'╌╌╎╎┌┐└┘',
+ 'single-d-2' : u'┄┄┆┆┌┐└┘',
+ 'single-d-3' : u'┈┈┊┊┌┐└┘',
+ 'single-thick' : u'━━┃┃┏┓┗┛',
+ 'single-thick-d-1' : u'╍╍╏╏┏┓┗┛',
+ 'single-thick-d-2' : u'┅┅┇┇┏┓┗┛',
+ 'single-thick-d-3' : u'┉┉┋┋┏┓┗┛',
+ 'single-r' : u'──││╭╮╰╯',
+ 'double' : u'══║║╔╗╚╝',
+ 'double-h' : u'══││╒╕╘╛',
+ 'double-v' : u'──║║╓╖╙╜',
+ 'double-tl' : u'═─║│╔╕╙┘',
+ 'double-tl-r' : u'═─║│╔╕╙╯',
+ 'double-tr' : u'═─│║╒╗└╜',
+ 'double-tr-r' : u'═─│║╒╗╰╜',
+ 'double-bl' : u'─═║│╓┐╚╛',
+ 'double-bl-r' : u'─═║│╓╮╚╛',
+ 'double-br' : u'─═│║┌╖╘╝',
+ 'double-br-r' : u'─═│║╭╖╘╝',
+ 'block-full' : u'████████',
+ 'block-full-r' : u'████▟▙▜▛',
+ 'block-half' : u'▄▀▐▌▗▖▝▘',
+ 'block-half-tb' : u'▄▀██▄▄▀▀',
+ 'block-half-o' : u'▀▄▌▐▛▜▙▟',
+ 'block-half-o-tb' : u'▀▄██████',
+ 'none' : u' ',
+ 'custom' : None,
+ }
+
def __init__(self, original_widget, title="",
tlcorner=None, tline=None, lline=None,
trcorner=None, blcorner=None, rline=None,
- bline=None, brcorner=None):
+ bline=None, brcorner=None, style=None, style_chars=None):
"""
Draw a line around original_widget.
Use 'title' to set an initial title text with will be centered
on top of the box.
- You can also override the widgets used for the lines/corners:
+ You can also apply attributes to the lines/corners:
tline: top line
bline: bottom line
lline: left line
@@ -119,9 +159,32 @@ class LineBox(WidgetDecoration, WidgetWrap):
trcorner: top right corner
blcorner: bottom left corner
brcorner: bottom right corner
+
+ Use 'style' to choose style from predefined styles. See LineBox.STYLES.
+
+ Use 'style_chars' to set characters for lines/corners and set 'style' to
+ 'custom' to take effective. 'style_chars' should be a string with eight
+ characters for as same order as for attributes above.
"""
self.title_widget = Text(self.format_title(title))
+ WidgetDecoration.__init__(self, original_widget)
+ self.set_style(style, style_chars,
+ tlcorner, tline, lline, trcorner,
+ blcorner, rline, bline, brcorner)
+ def set_style(self, style=None, style_chars=None,
+ tlcorner=None, tline=None, lline=None,
+ trcorner=None, blcorner=None, rline=None,
+ bline=None, brcorner=None):
+ if not style:
+ style = 'single' if get_encodeing_mode() == 'utf8' else 'ascii'
+ if style != 'custom':
+ style_chars = LineBox.STYLES[style]
+ ctline, cbline, clline, crline, \
+ ctlcorner, ctrcorner, cblcorner, cbrcorner = style_chars
+ self.style = style
+ self.style_chars = style_chars
+
def use_attr( a, t ):
if a is not None:
t = AttrWrap(t, a)
@@ -130,31 +193,31 @@ class LineBox(WidgetDecoration, WidgetWrap):
return t
self.tline_widget = Columns([
- Divider(self.ACS_HLINE),
+ Divider(ctline),
('flow', self.title_widget),
- Divider(self.ACS_HLINE),
+ Divider(ctline),
])
tline = use_attr( tline, self.tline_widget)
- bline = use_attr( bline, Divider(self.ACS_HLINE))
- lline = use_attr( lline, SolidFill(self.ACS_VLINE))
- rline = use_attr( rline, SolidFill(self.ACS_VLINE))
- tlcorner = use_attr( tlcorner, Text(self.ACS_ULCORNER))
- trcorner = use_attr( trcorner, Text(self.ACS_URCORNER))
- blcorner = use_attr( blcorner, Text(self.ACS_LLCORNER))
- brcorner = use_attr( brcorner, Text(self.ACS_LRCORNER))
+ bline = use_attr( bline, Divider(cbline))
+ lline = use_attr( lline, SolidFill(clline))
+ rline = use_attr( rline, SolidFill(crline))
+ tlcorner = use_attr( tlcorner, Text(ctlcorner))
+ trcorner = use_attr( trcorner, Text(ctrcorner))
+ blcorner = use_attr( blcorner, Text(cblcorner))
+ brcorner = use_attr( brcorner, Text(cbrcorner))
+
top = Columns([ ('fixed', 1, tlcorner),
tline, ('fixed', 1, trcorner) ])
middle = Columns( [('fixed', 1, lline),
- original_widget, ('fixed', 1, rline)], box_columns = [0,2],
+ self.original_widget, ('fixed', 1, rline)], box_columns = [0,2],
focus_column = 1)
bottom = Columns([ ('fixed', 1, blcorner),
bline, ('fixed', 1, brcorner) ])
pile = Pile([('flow',top),middle,('flow',bottom)],
focus_item = 1)
- WidgetDecoration.__init__(self, original_widget)
- WidgetWrap.__init__(self, pile)
+ self._set_w(pile)
def format_title(self, text):
if len(text) > 0:
--
1.7.3.4
From 5975e770ae10a23bf0d188aa0c742dc4cd0852d5 Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Thu, 28 Jul 2011 11:12:13 +0800
Subject: [PATCH 2/3] fix typo in called function name
---
urwid/graphics.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/urwid/graphics.py b/urwid/graphics.py
index e13ad8f..df3ad3d 100755
--- a/urwid/graphics.py
+++ b/urwid/graphics.py
@@ -177,7 +177,7 @@ class LineBox(WidgetDecoration, WidgetWrap):
trcorner=None, blcorner=None, rline=None,
bline=None, brcorner=None):
if not style:
- style = 'single' if get_encodeing_mode() == 'utf8' else 'ascii'
+ style = 'single' if get_encoding_mode() == 'utf8' else 'ascii'
if style != 'custom':
style_chars = LineBox.STYLES[style]
ctline, cbline, clline, crline, \
--
1.7.3.4
From 6d9df852efc6c44d1a205248ea1817170ca3a3e0 Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Tue, 6 Sep 2011 14:09:52 +0800
Subject: [PATCH 3/3] Last small changes before killing this branch and repo.
will put a formatted patch on Gist if the deletion causes code/commits
missing. I think GitHub does duplicate code at where pull requests are
opened. But just be safe.
---
urwid/graphics.py | 14 +++-----------
1 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/urwid/graphics.py b/urwid/graphics.py
index df3ad3d..f51163b 100755
--- a/urwid/graphics.py
+++ b/urwid/graphics.py
@@ -92,19 +92,11 @@ class BigText(FixedWidget):
class LineBox(WidgetDecoration, WidgetWrap):
- # Unused after adding predefined styles
- ACS_HLINE = u'─'
- ACS_VLINE = u'│'
- ACS_ULCORNER = u'┌'
- ACS_URCORNER = u'┐'
- ACS_LLCORNER = u'└'
- ACS_LRCORNER = u'┘'
-
- STYLES = { # tblrttbb
- # lrlr
+ STYLES = { # tblrttbb
+ # lrlr
'ascii' : u'--||++++', # default for non-UTF-8
- 'ascii-double' : u'==||++++', # default for non-UTF-8
+ 'ascii-double' : u'==||++++',
'ascii-slash' :ur'--||/\\/',
'ascii-wave' : u'~~||~~~~',
'ascii-dots' : u'........',
--
1.7.3.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment