Blog entries

  • Command-line graphical user interfaces

    2008/09/01 by Nicolas Chauvat
    http://azarask.in/gfx/ubiquity_side.png

    Graphical user interfaces help command discovery, while command-line interfaces help command efficiency. This article tries to explain why. I reached it when reading the list of references from the introduction to Ubiquity, which is the best extension to firefox I have seen so far. I expect to start writing Ubiquity commands soon, since I have already been using extensively the 'keyword shorcut' functionnality of firefox's bookmarks and we have already done work in the area of 'language interaction', as they call it at Mozilla Labs, when working with Narval. Our Logilab Simple Desktop project, aka simpled, also goes in the same direction since it tries to unify different applications into a coherent work environment by defining basic commands and shorcuts that can be applied everywhere and accessing the rest of the functionnalities via a command-line interface.


  • Generating a user interface from a Yams model

    2012/01/09 by Nicolas Chauvat

    Yams is a pythonic way to describe an entity-relationship model. It is used at the core of the CubicWeb semantic web framework in order to automate lots of things, including the generation and validation of forms. Although we have been using the MVC design pattern to write user interfaces with Qt and Gtk before we started CubicWeb, we never got to reuse Yams. I am on my way to fix this.

    Here is the simplest possible example that generates a user interface (using dialog and python-dialog) to input data described by a Yams data model.

    First, let's write a function that builds the data model:

    def mk_datamodel():
        from yams.buildobjs import EntityType, RelationDefinition, Int, String
        from yams.reader import build_schema_from_namespace
    
        class Question(EntityType):
            number = Int()
            text = String()
    
        class Form(EntityType):
            title = String()
    
        class in_form(RelationDefinition):
            subject = 'Question'
            object = 'Form'
            cardinality = '*1'
    
        return build_schema_from_namespace(vars().items())
    

    Here is what you get using graphviz or xdot to display the schema of that data model with:

    import os
    from yams import schema2dot
    
    datamodel = mk_datamodel()
    schema2dot.schema2dot(datamodel, '/tmp/toto.dot')
    os.system('xdot /tmp/toto.dot')
    
    http://www.logilab.org/file/87002?vid=download

    To make a step in the direction of genericity, let's add a class that abstracts the dialog API:

    class InterfaceDialog:
        """Dialog-based Interface"""
        def __init__(self, dlg):
            self.dlg = dlg
    
        def input_list(self, invite, options) :
            assert len(options) != 0, str(invite)
            choice = self.dlg.radiolist(invite, list=options, selected=1)
            if choice is not None:
                return choice.lower()
            else:
                raise Exception('operation cancelled')
    
        def input_string(self, invite, default):
            return self.dlg.inputbox(invite, init=default).decode(sys.stdin.encoding)
    

    And now let's put everything together:

    datamodel = mk_datamodel()
    
    import dialog
    ui = InterfaceDialog(dialog.Dialog())
    ui.dlg.setBackgroundTitle('Dialog Interface with Yams')
    
    objs = []
    for entitydef in datamodel.entities():
        if entitydef.final:
            continue
        obj = {}
        for attr in entitydef.attribute_definitions():
            if attr[1].type in ('String','Int'):
                obj[str(attr[0])] = ui.input_string('%s.%s' % (entitydef,attr[0]), '')
        try:
            entitydef.check(obj)
        except Exception, exc:
            ui.dlg.scrollbox(str(exc))
    
    print objs
    
    http://www.logilab.org/file/87001?vid=download

    The result is a program that will prompt the user for the title of a form and the text/number of a question, then enforce the type constraints and display the inconsistencies.

    The above is very simple and does very little, but if you read the documentation of Yams and if you think about generating the UI with Gtk or Qt instead of dialog, or if you have used the form mechanism of CubicWeb, you'll understand that this proof of concept opens a door to a lot of possibilities.

    I will come back to this topic in a later article and give an example of integrating the above with pigg, a simple MVC library for Gtk, to make the programming of user-interfaces even more declarative and bug-free.