It's about time for another of my yearly personal blog posts. This time I'll be covering a creative approach that I took to implementing a feature.
The feature: EMPC has a filesystem view which displays a gengrid of all available music. When the user types while this view is active, an entry appears to search for entities in the current directory. While the entry is active, however, the user should also be able to continue using the arrow keys to navigate. Also, there is no cursor in this entry so allowing left/right arrows to move the cursor position is something that must be avoided.
The problem: This seemingly requires splitting focus between the gengrid widget and the entry widget and redirecting certain key presses to each widget. EFL does not permit this type of focus splitting, and attempting to redirect key presses to various widgets is not smart.
First attempt: Initially I figured I'd just let Elementary figure out focus and things would "magically work". I added object key callbacks for both the gengrid and the entry; the gengrid would append to the entry for keys with compose strings, and the entry would operate as usual. Both callbacks had handling code for special keys Escape/Return/Enter which would hide the entry.
Minor success: The arrow keys still functioned as expected, typing continued incrementing the search as expected, and hiding the entry worked as expected.
Major failure: Pressing backspace, which has a valid compose string ("\b"), would cause invalid characters to be added to the entry, and the user would have to start over. Also, other entry keybinds (eg. ctrl+a) would never work as expected. The entry was never receiving focus (thanks elm!), and it would have blocked arrow navigation if it had worked as I expected.
Second attempt: After tossing out a few more failure ideas, I came to the conclusion that there was no way to do this which did not involve the entry itself having focus at all times. Compose, backspace, and shortcut handling is all done in edje internals, and I had no desire to face the efl repo commit message ghestapo unnecessarily by breaking out such features as utility functions. Nor did I want to do any shenanigans with changing the focus object during key press and faking the input object path. No, my path was simpler. I would create an ecore key event handler before the elementary event handler.
To do this requires some knowledge of efl init internals and ordering, but the basic idea is that you manually call ecore_event_init() before elm_init(), set up whatever input event handlers you want (eg. ECORE_EVENT_KEY_DOWN), and then call elm_init(). In the corresponding handler, you can then return 0/false/EINA_FALSE/ECORE_CALLBACK_DONE/ECORE_CALLBACK_CANCEL to prevent the event from being propagated any farther down the canvas. So now, when the entry is active, focus is disallowed on the gengrid to force it onto the entry, and then the arrow keys are filtered in my pre-event handler.
The downside here is that gengrid is another failure widget which lacks a lot of functionality/testing, and so there are no externally accessible functions for navigating directionally. Since there is the constant talk of scrapping gengrid, I opted to write a simple algorithm in my app to calculate and find the target item xy coordinates using elm_gengrid_item_pos_get() with some iteration.
Success: Everything is working as expected, and the related event filtering code can be found here, while the gengrid item navigation code is here.
Overall this was a clever solution to the issue, but not necessarily a great one. I've used this technique for a number of input-related issues in EMPC, and it feels hacky in every case. I think that ideally there should probably be a more intuitive way of doing input blocking and filtering which doesn't require the awful key grab api in evas.
title
Tuesday, March 10, 2015
Sunday, May 4, 2014
Almost there...
I made another video of my music player to demonstrate a few more features which were left out of the previous video. In the process, I uncovered and fixed more bugs. I also found that I seem to have borked Edje text sizing, as seen briefly in the tooltips.
Notes:
- Software rendering hurts a lot here. First Music Player GUI Ever To Require Hardware Acceleration For Smooth Performance was not the tagline that I was shooting for.
- First two cover art images (first Periphery:Clear cover, Odyssey cover) are being loaded from a disk cache. Every other image is being searched for and downloaded in realtime.
- File browser uses Glyr for artist image finding, which is horrifically slow/inaccurate => this is why the file browser is blank. Need to figure out a non-Google service to abuse for this...
- Lyrics were downloaded in realtime
1.0 soon, no I'm not adding non-MPD support.
Tuesday, April 22, 2014
Things That End In 'C'
I've been doing a lot of Edje work lately, and maybe I'll make a post about that at some point. Or about anything. But until then, here's a video of my music player:
Sunday, January 19, 2014
App Development & Me: A Brief History With Infographics And Supplementary Readings As Well As A Look Into The Future
Fed up with the constant GTK3-related downward spiral of GMPC (which I have been using for 6+ years), last month I started writing my own music player. I know what you're saying:
Why write an EFL app which isn't an image viewer?
Well the short answer is...I didn't. It displays images. So don't worry about that. We'll come back to apps, but first let's take a look into some history.
I've written a number of EFL apps in the past. The thing is, mostly I just write them for my own use. I needed a photo viewer and XV wasn't available, so I wrote EV. I was linking lots of images in chat, so I wrote Shotgun and then started on its successor, S2, so I could have tooltips of all the gifs without needing to click them. I even wrote an RSS aggregating daemon, eRSSd, on a request with the intent to build a nice gadget around it, which I'll probably get back to sometime next year.
All these things have something in common: they were functional. I mean this in the sense of function vs. form--they served their purposes, but they didn't necessarily look great while doing it.
This is a bit of a problem, I suppose, given that I work so much with UI stuff while working on Enlightenment. People see that I'm writing an app, they know that there are very few EFL-based apps (Terminology, that other one, uhh...), and so they expect great things. Then I get a deluge of Gustavos saying "Hey nice app, kid, did you make it with TK?" While such things are always amusing, it seems like the idea of making "self use" apps which are moderately complex, such as an XMPP client, is Not Smart. Or at least, that's the idea that other people have tried to convey. I'm not going anywhere with this, it's my personal development blog so I get to ramble if I feel like it.
So that brings me to the present-ish. After the amazing people over at SRA were nice enough to take in a lowly release manager, I found myself with a small amount of both time and sanity to spare. Naturally, to fix both of these things I decided to write another app, and to make that app look good. Also I merged the 6+-month old E19 branch, creating $Texas bugs and causing me to spend well over 70 hours in the past week doing emergency cleanup.
Now that I'm writing another app, and a music player(ish) one at that, the obvious first question that most people would ask is "How should it look?" Amateurs. The first question I asked myself was "How can I massively overengineer this?" Those people who are in the know about my previous development history can probably guess the answer.
Empeedee, as I am calling the initial project, is a client-server package for MPD. "Why MPD and not XMMS2?" asked one random stalker. I use MPD. I've used MPD for almost 10 years, and I don't see myself ever not using it unless something similar-but-better is written. If I'm in a place where it's not practical to set up MPD, I use a piped mplayer for gapless playback. Look it up.
MPD has what I would consider a bit of a design flaw: it doesn't have any concept of subscriptions or PUSH data. This means that it's completely passive, only providing information/data when explicit requests have been made, and then only to the client which has made the request. If you're using a system and want to have updated information in a couple places, such as a gadget and an app, this means you've got to spam MPD with status requests multiple times a second from each client--hardly ideal even if MPD is able to handle a number of clients doing this simultaneously.
My approach was a bit different: create a daemon to do the connection to MPD, and then use DBus to interact with that and broadcast it to anyone listening. This reduces overall CPU usage since additional clients get the same data for free. Obviously this approach isn't as useful if you're only going to have one app running against MPD, but it does make writing that app much easier, I've discovered, since I can use autogenerated DBus bindings and keep everything asynchronous with ease.
Anyway, last month I started the project. This was the result (26 Dec 2013):
I use the darkness theme on my desktop along with its accompanying elm theme, which is why it's black instead of gray. And yes, I redid the slider theme after taking that shot.
Now this obviously isn't anywhere near a great-looking app. I wanted to get something functional and non-crashy in place before I took some time to work on aesthetics. Every element in the UI here is functional and works as expected, so that was a great foundation to start with.
I used EMPC daily after this point, mostly as a nice way to display MPD status in a smaller window on my IRC desktop since GMPC needs to be run fullscreen to be useful. Lots of things happened over the next month, and then I was struck by the need to get back to it over the past few days, possibly due to the arrival of the incredibly catchy Clear album by Periphery, which I'm looking forward to purchasing legitimately in a few days. Here's another shot from 18 Jan 2014 after a few hours of work and introducing some custom EDC:
The cover art just copies the GMPC/GLYR database (sqlite, vomit) info using Esskyuehl. I had a great time working with ESQL again after being away from it for so long, and it worked perfectly right out of the git with only one bug in the sqlite part itself. The extremely hackish module for getting this data is about 170 lines, 40 of which are lines of enums copied from GLYR and another 20 for the SQL query.
I spent some time experimenting with text here before arriving at the conclusion that it just wasn't going to be possible to display the playlist over the album art like this due to coloring. This album art was especially good since it was very light-colored, which caused my normal bright-colored text preference to fall on its face. Edje doesn't yet provide many options for outlining or related effects to make text stand out here, so I had to think of something else. Also there were still the gross widgets at the top to do away with.
Later the same day this happened:
I've got a custom slider style in action at the bottom, and all the buttons have been moved offscreen. Artist/Album/Title/Track are now easily visible, and the current time is stuck in the middle because I hadn't figured out what to do with it then.
Less than an hour later:
This is basically the same as the previous version except that the alignment of the text and slider at the bottom is a little more accurate. I don't remember why I updated the screenshot.
At this point I had also really fleshed out the overlays:
This is actually two separate overlays: the bottom one holds the control buttons and moves up and down (pushing the slider and text with it), and the playlist is a scrolling 3 column custom genlist which slides in/out from/to the right along with the translucent underlay so the text is readable. Both toggle automatically based on mouse movements and also can be manually toggled by pressing F1, which is sort of the same as GMPC.
After more tweaking today, I finally ended up with something I'm moderately pleased with:
The time now displays and updates only on the overlay, which enabled me to remove it from the main screen. Also I added some super hacks to the slider to make it look super cool, though this isn't visible from a screenshot.
I've still got a lot to do here: the metadata fetcher needs to be an actual module instead of a compiled-in, repeat/consume/single mode toggle elements need to be added, and I should probably add file selection capabilities at some point so I can do more than just delete items from the current playlist without having to go to another client.
Based on this, I'd say that app development with EFL is definitely possible with the current libraries. Some of the more subtle animations that I wanted to do were tricky to implement, but none of this was anything that I'd consider challenging, so maybe others will be inspired to try working on their own EFL apps after reading these ramblings.
I should probably blog here more frequently, but I seldom work on my own projects any more so there isn't usually a lot to talk about.
Why write an EFL app which isn't an image viewer?
Well the short answer is...I didn't. It displays images. So don't worry about that. We'll come back to apps, but first let's take a look into some history.
I've written a number of EFL apps in the past. The thing is, mostly I just write them for my own use. I needed a photo viewer and XV wasn't available, so I wrote EV. I was linking lots of images in chat, so I wrote Shotgun and then started on its successor, S2, so I could have tooltips of all the gifs without needing to click them. I even wrote an RSS aggregating daemon, eRSSd, on a request with the intent to build a nice gadget around it, which I'll probably get back to sometime next year.
All these things have something in common: they were functional. I mean this in the sense of function vs. form--they served their purposes, but they didn't necessarily look great while doing it.
This is a bit of a problem, I suppose, given that I work so much with UI stuff while working on Enlightenment. People see that I'm writing an app, they know that there are very few EFL-based apps (Terminology, that other one, uhh...), and so they expect great things. Then I get a deluge of Gustavos saying "Hey nice app, kid, did you make it with TK?" While such things are always amusing, it seems like the idea of making "self use" apps which are moderately complex, such as an XMPP client, is Not Smart. Or at least, that's the idea that other people have tried to convey. I'm not going anywhere with this, it's my personal development blog so I get to ramble if I feel like it.
So that brings me to the present-ish. After the amazing people over at SRA were nice enough to take in a lowly release manager, I found myself with a small amount of both time and sanity to spare. Naturally, to fix both of these things I decided to write another app, and to make that app look good. Also I merged the 6+-month old E19 branch, creating $Texas bugs and causing me to spend well over 70 hours in the past week doing emergency cleanup.
Now that I'm writing another app, and a music player(ish) one at that, the obvious first question that most people would ask is "How should it look?" Amateurs. The first question I asked myself was "How can I massively overengineer this?" Those people who are in the know about my previous development history can probably guess the answer.
Empeedee, as I am calling the initial project, is a client-server package for MPD. "Why MPD and not XMMS2?" asked one random stalker. I use MPD. I've used MPD for almost 10 years, and I don't see myself ever not using it unless something similar-but-better is written. If I'm in a place where it's not practical to set up MPD, I use a piped mplayer for gapless playback. Look it up.
MPD has what I would consider a bit of a design flaw: it doesn't have any concept of subscriptions or PUSH data. This means that it's completely passive, only providing information/data when explicit requests have been made, and then only to the client which has made the request. If you're using a system and want to have updated information in a couple places, such as a gadget and an app, this means you've got to spam MPD with status requests multiple times a second from each client--hardly ideal even if MPD is able to handle a number of clients doing this simultaneously.
My approach was a bit different: create a daemon to do the connection to MPD, and then use DBus to interact with that and broadcast it to anyone listening. This reduces overall CPU usage since additional clients get the same data for free. Obviously this approach isn't as useful if you're only going to have one app running against MPD, but it does make writing that app much easier, I've discovered, since I can use autogenerated DBus bindings and keep everything asynchronous with ease.
Anyway, last month I started the project. This was the result (26 Dec 2013):
EMPC V1 - Widgets! |
Now this obviously isn't anywhere near a great-looking app. I wanted to get something functional and non-crashy in place before I took some time to work on aesthetics. Every element in the UI here is functional and works as expected, so that was a great foundation to start with.
I used EMPC daily after this point, mostly as a nice way to display MPD status in a smaller window on my IRC desktop since GMPC needs to be run fullscreen to be useful. Lots of things happened over the next month, and then I was struck by the need to get back to it over the past few days, possibly due to the arrival of the incredibly catchy Clear album by Periphery, which I'm looking forward to purchasing legitimately in a few days. Here's another shot from 18 Jan 2014 after a few hours of work and introducing some custom EDC:
EMPC V2 - BLARGH! |
I spent some time experimenting with text here before arriving at the conclusion that it just wasn't going to be possible to display the playlist over the album art like this due to coloring. This album art was especially good since it was very light-colored, which caused my normal bright-colored text preference to fall on its face. Edje doesn't yet provide many options for outlining or related effects to make text stand out here, so I had to think of something else. Also there were still the gross widgets at the top to do away with.
Later the same day this happened:
EMPC V3 - What's that thing in the middle? |
Less than an hour later:
EMPC V4 - Not noticeably different |
At this point I had also really fleshed out the overlays:
EMPC V4 - Overlays open |
After more tweaking today, I finally ended up with something I'm moderately pleased with:
EMPC V4 - Overlays open, song selected |
I've still got a lot to do here: the metadata fetcher needs to be an actual module instead of a compiled-in, repeat/consume/single mode toggle elements need to be added, and I should probably add file selection capabilities at some point so I can do more than just delete items from the current playlist without having to go to another client.
Based on this, I'd say that app development with EFL is definitely possible with the current libraries. Some of the more subtle animations that I wanted to do were tricky to implement, but none of this was anything that I'd consider challenging, so maybe others will be inspired to try working on their own EFL apps after reading these ramblings.
I should probably blog here more frequently, but I seldom work on my own projects any more so there isn't usually a lot to talk about.
Monday, April 1, 2013
eRSSd
After saying I'd do it for quite a while, I finally made some progress in my promise to write some E-related RSS stuff for Boris Faure, aka 'billiob': eRSSd is in git now, and it's moderately tested and (should be) fully functional.
Methodology
Originally, Boris was working on a standalone app called ERSS on github. I chipped in a tiny bit to improve his Azy usage, since it's the easiest way to get and parse RSS feeds, but then, as E developers tend to do, I drifted away from the project and absolutely did not forget about it.
Over the time that I wasn't working on it, I wrote a ton of other projects and contributed to even more. Along the way, I realized that what would be great for RSS was if we had an underlying daemon which could then be accessed by all the apps and widgets, and which could run in a distributed fashion by synchronizing with other daemons over a network.
Implementation
The hardest part of any project, aside from naming it, is starting the work. Aside from working out a number of kinks in Azy related to HTTP/1.1 chunked encoding, the whole thing was written in a weekend. During this process, I spent some time learning the ins and outs of the new dbus integration library, edbus2. It's certainly an improvement over the original, which was basically just libdbus, but it still feels pretty rough around the edges; iterators in particular are not great to work with.
Anyway, the basics of eRSSd:
Adding feeds
* Add a feed from cmdline of daemon or over dbus (or remote api once I iron it out)
* Feed is fetched and cached using eet
* Feed and items become available for use over dbus (and remote API)
Using feeds
* Feed is fetched on interval based on various http/rss attributes which indicate optimal cache length
* dbus signals sent to indicate freshness and new items
* Clients use eet to directly read cache file using local client API wrapper to avoid sending tons of data over socket
* Clients send signals back to daemon to mark items/feeds as read
Deleting feeds
* Client calls dbus delete method on daemon with URL for feed
* Daemon deletes feed, removes cache
* Signals sent over dbus (and remote) to indicate deletion of feed so UIs can be updated
A utility library for clients is provided, allowing developers to avoid having to write any eet/edbus2 code themselves and focus entirely on presentation/usage. At present, only a dummy configuration UI exists, but plans are in motion to create some cool stuff in the near future. RSS is a useful and common enough tool that we should spend some effort integrating it more!
Methodology
Originally, Boris was working on a standalone app called ERSS on github. I chipped in a tiny bit to improve his Azy usage, since it's the easiest way to get and parse RSS feeds, but then, as E developers tend to do, I drifted away from the project and absolutely did not forget about it.
Over the time that I wasn't working on it, I wrote a ton of other projects and contributed to even more. Along the way, I realized that what would be great for RSS was if we had an underlying daemon which could then be accessed by all the apps and widgets, and which could run in a distributed fashion by synchronizing with other daemons over a network.
Implementation
The hardest part of any project, aside from naming it, is starting the work. Aside from working out a number of kinks in Azy related to HTTP/1.1 chunked encoding, the whole thing was written in a weekend. During this process, I spent some time learning the ins and outs of the new dbus integration library, edbus2. It's certainly an improvement over the original, which was basically just libdbus, but it still feels pretty rough around the edges; iterators in particular are not great to work with.
Anyway, the basics of eRSSd:
Adding feeds
* Add a feed from cmdline of daemon or over dbus (or remote api once I iron it out)
* Feed is fetched and cached using eet
* Feed and items become available for use over dbus (and remote API)
Using feeds
* Feed is fetched on interval based on various http/rss attributes which indicate optimal cache length
* dbus signals sent to indicate freshness and new items
* Clients use eet to directly read cache file using local client API wrapper to avoid sending tons of data over socket
* Clients send signals back to daemon to mark items/feeds as read
Deleting feeds
* Client calls dbus delete method on daemon with URL for feed
* Daemon deletes feed, removes cache
* Signals sent over dbus (and remote) to indicate deletion of feed so UIs can be updated
A utility library for clients is provided, allowing developers to avoid having to write any eet/edbus2 code themselves and focus entirely on presentation/usage. At present, only a dummy configuration UI exists, but plans are in motion to create some cool stuff in the near future. RSS is a useful and common enough tool that we should spend some effort integrating it more!
Sunday, August 26, 2012
bits and pieces
finally getting back to some theme stuff; gotta get darkness e/elm into shape before The Big Release (TBR). new hoversel theme:
needs a little tweaking so the edge image doesn't overflow the hover, but I'll tackle that another day when I care more
needs a little tweaking so the edge image doesn't overflow the hover, but I'll tackle that another day when I care more
Monday, July 16, 2012
New Footrest
So I got a mail at work earlier today stating that I had received a package. It was so incredible that I thought I would share: behold, my new footrest!
Subscribe to:
Posts (Atom)