def create(p_class, p_todo, p_id_width=4):
        """
        Creates a TodoWidget instance for the given todo. Widgets are
        cached, the same object is returned for the same todo item.
        """

        def parent_progress_may_have_changed(p_todo):
            """
            Returns True when a todo's progress should be updated because it is
            dependent on the parent's progress.
            """
            return p_todo.has_tag('p') and not p_todo.has_tag('due')

        source = p_todo.source()

        if source in p_class.cache:
            widget = p_class.cache[source]

            if p_todo is not widget.todo:
                # same source text but different todo instance (could happen
                # after an edit where a new Todo instance is created with the
                # same text as before)
                # simply fix the reference in the stored widget.
                widget.todo = p_todo

            if parent_progress_may_have_changed(p_todo):
                widget.update_progress()
        else:
            widget = p_class(p_todo, p_id_width)
            p_class.cache[source] = widget

        return widget
Creates a TodoWidget instance for the given todo. Widgets are
        cached, the same object is returned for the same todo item.