Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.8 topics #1783

Closed
4 of 5 tasks
zeffii opened this issue Sep 13, 2017 · 52 comments
Closed
4 of 5 tasks

2.8 topics #1783

zeffii opened this issue Sep 13, 2017 · 52 comments

Comments

@zeffii
Copy link
Collaborator

zeffii commented Sep 13, 2017

This issue hopes to collect major Blender Python API changes that may or may not affect sverchok.

see: https://wiki.blender.org/index.php/Dev:2.8/Source/Python/UpdatingScripts

  • 2.8 will drop the bpy.utils.register_module function, this doesn't affect us much..or maybe at all.
  • 2.8 will enforce a naming convention for bl_idname of operators/menus/headers/panels and uiLists.
    • We will need to update these, and could already start gradually migrating over to make the final 2.8 step easier. Big task but very boring/scriptable.
  • 2.8 the event handlers we rely on are gone, but I suspect appropriate alternatives will be supplied or we really have to focus purely on update=updateNode to traverse the graph.
  • 2.8 things we rely on for any bgl drawing ( stethoscope, vdmk2, indexviewer ) are all impacted.
  • 2.8 no longer allows arbitrary assignments to bpy.types (small task- done!)
  • 2.8 registering classes, node class references not automatically located in bpy.types (big task- done!)

Regisering classes

A suggestion on that page gives: ( i like this.. we can use this a lot..can even use our own version of this for pre 2.8 sverchok ..)

classes = (
    FooClass,
    BarClass,
    BazClass,
)
register, unregister = bpy.utils.register_classes_factory(classes)  # not yet (or ever?) in 2.79

this will work for most node files, i'm not immediately aware that any nodes register scene variables directly in register (but there might be one or two)

bl_idname

...

BGL

a few bgl functions that we use are now dropped from bgl. I'm not sure how large the impact on the drawing code is. Good opportunity to write a new Viewer node.
see : https://gamedev.stackexchange.com/questions/34108/opengl-vbo-or-glbegin-glend

@zeffii zeffii added this to the 2.8 milestone Sep 13, 2017
@zeffii
Copy link
Collaborator Author

zeffii commented Sep 13, 2017

i might not be available to do any of this.

@nortikin
Copy link
Owner

why?

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 13, 2017

external pressures :/

@nortikin
Copy link
Owner

what does mean will enforce a naming convention for bl_idname of operators/menus/headers/panels and uiLists. ?
what exact changes in bl_idname we need to do?

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 22, 2017

not sure from what I understand

  • menus will become SV_MT_SomeMenu
  • operators will become SV_OT_SomeOperator.
  • panels.. SV_PT_SomePanel. etc

( not a massive issue... but if we don't follow the new convention it will be lifeless )

Not sure if or how Node subclasses will be treated. Lukily we already prefix most of those anyway :)

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 22, 2017

we can definitely already migrate menus/operators and panel to be consistent with the regex Blender will use:

pattern = `[A-Z][A-Z0-9_]*_MT_[A-Za-z0-9_]+`

@enzyme69
Copy link
Collaborator

enzyme69 commented Sep 22, 2017 via email

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 22, 2017

2.8 doesn't draw the nodeview properly on my crappy Lenovo laptop. I've been told to wait about 6 months before taking 2.8 serious enough to work on GL code.

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 22, 2017

if we keep up to date with 2.79 nightly builder bot builds the final step-over to 2.8 will be less of a jump.

@DolphinDream
Copy link
Collaborator

External pressure :) Like a comet set on direct path with Earth ? :)

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 27, 2017

Like a comet set on direct path with Earth ?

comets. the universe's answer to ignorance :)

@nortikin
Copy link
Owner

Bl_idname. What to do? Not clear to me. Where to read?

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 28, 2017

The link at the top @nortikin is all the information we've been given. But .. for example

# SvMoveSocketOpExp(Operator, MonadOpCommon)
SvMoveSocketOpExp -> SV_OT_MoveSocketOpExp

@zeffii
Copy link
Collaborator Author

zeffii commented Sep 28, 2017

I am not sure if we need to manually pass

bl_idname = "node.sverchok_move_socket_exp"

it might already default to something else if we don't.

# bl_idname = "ops.SV_OT_MoveSocketOpExp"

will need to experiment.

@Theverat
Copy link

Oops, I didn't know github would create a notice here if I linked this issue from my repository, sorry.

Since I'm here already:
If a class does not define a bl_idname, the class name is used as bl_idname.

@Durman
Copy link
Collaborator

Durman commented Jun 1, 2018

Changing in user interface:

Alt text

@enzyme69
Copy link
Collaborator

enzyme69 commented Jun 1, 2018 via email

@nortikin
Copy link
Owner

nortikin commented Jun 3, 2018

 File "/home/ololo/.config/blender/2.80/scripts/addons/sverchok/__init__.py", line 77, in <module>
    imported_modules = init_architecture(__name__, utils_modules, ui_modules)
  File "/home/ololo/.config/blender/2.80/scripts/addons/sverchok/core/__init__.py", line 99, in init_architecture
    import_settings(imported_modules, sv_name)
  File "/home/ololo/.config/blender/2.80/scripts/addons/sverchok/core/__init__.py", line 80, in import_settings
    settings = importlib.import_module(".settings", sv_dir_name)
  File "/home/ololo/Downloads/INSTALL/blender-2.80-35efa1d3d33-linux-glibc219-x86_64/2.80/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/home/ololo/.config/blender/2.80/scripts/addons/sverchok/settings.py", line 8, in <module>
    from sverchok.core import handlers
  File "/home/ololo/.config/blender/2.80/scripts/addons/sverchok/core/handlers.py", line 10, in <module>
    from sverchok.ui import (
  File "/home/ololo/.config/blender/2.80/scripts/addons/sverchok/ui/viewer_draw_mk2.py", line 36, in <module>
    from bgl import (
ImportError: cannot import name 'glBegin'

@nortikin
Copy link
Owner

nortikin commented Jun 3, 2018

BGL go crazy

@Durman
Copy link
Collaborator

Durman commented Jun 9, 2018

@Durman
Copy link
Collaborator

Durman commented Jun 23, 2018

New node editor is coming:

Alt text

2018-06-23_22-15-46

2018-06-23_22-08-30

@portnov
Copy link
Collaborator

portnov commented Jul 2, 2018

2.8 is already alpha.
https://code.blender.org/2018/06/beyond-the-code-quest/
What is our status?

@Kosvor2
Copy link
Collaborator

Kosvor2 commented Jul 10, 2018

Sverchok can be forced to "work" on 2.8. But without all nodes what use BGL, and nodetree updates only on frame change. Also no way to link new objects to scene. Some icons missing. Here testing branch: https://github.com/nortikin/sverchok/commits/Blender-2.8-testing

@Durman
Copy link
Collaborator

Durman commented Jul 10, 2018

I heard on Blender Developers channel that it is too early to fix addons for Blender 2.8 if you don't want to make the work twice becouse API still is developing and can have changes.

@portnov
Copy link
Collaborator

portnov commented Jul 10, 2018

Yes, I received the same from them. It is okay... ish... The only thing I am worrying about is that there might be too small gap between "python api stabilization" and "blender release" dates for us to update sverchok.

@zeffii
Copy link
Collaborator Author

zeffii commented Jul 10, 2018

i think it's perfectly acceptable for a non trivial add-on (like Sverchok) to take some time to update. Once the scripting interface is ready for the bgl replacement.

i'm not going to spend time doing this, i wish others didn't either. ( i already did tests early on : https://github.com/nortikin/sverchok/tree/b28_test )

@nortikin
Copy link
Owner

nortikin commented Sep 1, 2018

https://developer.blender.org/T56644
need some conversation maybe they will tell us what is in plans
https://developer.blender.org/T49092 also here it is something going
As i see, All in nodes is not for 2.8

@nortikin
Copy link
Owner

nortikin commented Sep 1, 2018

https://devtalk.blender.org/t/everything-nodes-with-sverchok/2029 also they say it is better place.

@zeffii
Copy link
Collaborator Author

zeffii commented Oct 11, 2018

bgl now exists again in 2.8 nightly builds, but glBegin and _End are no longer supported

ImportError: cannot import name 'glBegin' from 'bgl' (unknown location)

seems like we must now construct proper VBO. i'll dig into this. :)

https://gist.github.com/ousttrue/c4ae334fc1505cdf4cd7

@Kosvor2
Copy link
Collaborator

Kosvor2 commented Oct 29, 2018

https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Draw_API#Examples

@zeffii
Copy link
Collaborator Author

zeffii commented Oct 29, 2018

looks like fun :)

@nortikin
Copy link
Owner

nortikin commented Nov 1, 2018

@nortikin
Copy link
Owner

nortikin commented Nov 1, 2018

https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Addons
from this:

2.7x:
class MyOperator(Operator):
    value = IntProperty()
2.8x:
class MyOperator(Operator):
    value: IntProperty()

and

   [A-Z][A-Z0-9_]*_MT_[A-Za-z0-9_]+
The separator for each class is listed below:
    Header -> _HT_
    Menu -> _MT_
    Operator -> _OT_
    Panel -> _PT_
    UIList -> _UL_
Valid Examples:
    OBJECT_OT_fancy_tool
    SOME_HEADER_HT_my_header
    PANEL123_PT_myPanel (lower case is preferred but mixed case is supported).
Access (bpy.types)
Classes registered by addons are no longer available in bpy.types. Instead addons can import their own modules and access the classes directly. 

Also not register_module, but register_class

classes = (
    FooClass,
    BarClass,
    BazClass,
)
register, unregister = bpy.utils.register_classes_factory(classes)

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 1, 2018

value: IntProperty() lol :/

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 1, 2018

__annotations__ = {}
__annotations__["some_property"] = IntProperty(....)

@nortikin
Copy link
Owner

nortikin commented Nov 1, 2018

well, if we acess own class, will it looks like:

sverchok.trees['__name__'].datasteps[3]=np.array([.....])

?
Could we process node trees in subprocess or threadig?

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 1, 2018

not sure.. but am tempted to start the port very soon. (and no backward compatibility... time for a fresh start? ) keep it very basic at the start.. only very few nodes.

@nortikin
Copy link
Owner

nortikin commented Nov 1, 2018

trying to call self for addon radiola.py 2.8
But it is no module 'radiola'
so i donno how to call sverchok from sverchok before register sverchok if i need to register it.

@nortikin
Copy link
Owner

nortikin commented Nov 1, 2018

bl_info = {
    "name": "Radiola",
    "author": "nikitron.cc.ua",
    "version": (0, 0, 1),
    "blender": (2, 8, 0),
    "location": "View3D > Tool Shelf > SV > Radiola",
    "description": "Play the radio",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Misc"}

import os
import signal
#import threading
import bpy
import time
import subprocess as sp
import radiola
print(dir(radiola))

class SV_OT_radiola(bpy.types.Operator):
    '''Radiola'''
    bl_idname = "sound.radiola"
    bl_label = "play radio"

    make: bpy.props.BoolProperty(name='make',default=False)
    clear: bpy.props.BoolProperty(name='clear',default=False)
    play: bpy.props.BoolProperty(name='play',default=True)
    item_play: bpy.props.IntProperty(name='composition',default=0)

    def execute(self, context):

        if self.clear:
            context.scene.rp_playlist.clear()
            context.window_manager.radiola_clear = True
            self.clear = False
            return {'FINISHED'} 
        if self.make:
            self.dolist(urls,names)
            context.window_manager.radiola_clear = False
            self.make = False
            return {'FINISHED'} 

        if not len(context.scene.rp_playlist):
            self.dolist(urls,names)
        url = context.scene.rp_playlist[self.item_play].url

        if self.play:
            music = sp.Popen(['/usr/bin/mplayer', url])
            context.window_manager.radiola_ind = self.item_play
            context.window_manager.radiola = music.pid
        else:
            os.kill(context.window_manager.radiola, signal.SIGTERM)
            #music.terminate()
        return {'FINISHED'} 

    def dolist(self,urls,names):
        for u,n in zip(urls,names):
            bpy.context.scene.rp_playlist.add()
            bpy.context.scene.rp_playlist[-1].url = u
            bpy.context.scene.rp_playlist[-1].name = n


class SV_PT_radiola_panel(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = "Radiola"
    bl_options = {'DEFAULT_CLOSED'}
    bl_category = 'SV'

    make: bpy.props.BoolProperty(name='make',default=False)
    clear: bpy.props.BoolProperty(name='clear',default=False)
    play: bpy.props.BoolProperty(name='play',default=True)
    item_play: bpy.props.IntProperty(name='composition',default=0)

    def draw(self, context):
        ''' \
        Radiola \
        '''
        layout = self.layout
        col = layout.column(align=True)
        col.scale_y = 1

        if radiola.radiola_clear:
            col.operator('sound.radiola',text='Make').make = True
        else:
            col.operator('sound.radiola',text='Clear').clear = True
        col = layout.column(align=True)
        col.scale_y = 3
        b = col.operator('sound.radiola',text='Stop')
        b.play=False
        playlist_print = [a.name for a in radiola.rp_playlist]
        i=0
        col = layout.column(align=True)
        col.scale_y = 1
        for p in playlist_print:
            i+=1
            if i == (radiola.radiola_ind+1):
                a = col.operator('sound.radiola', text='> '+str(i)+' | '+str(p))
                a.item_play=i-1
                a.play=True
            else:
                a = col.operator("sound.radiola", text='    '+str(i)+' | '+str(p))
                a.item_play=i-1
                a.play=True

class RP_Playlist(bpy.types.PropertyGroup):
    url: bpy.props.StringProperty()
    name: bpy.props.StringProperty()

urls = [    'http://icecast.vgtrk.cdnvideo.ru/vestifm_mp3_192kbps',
            'http://strm112.1.fm/atr_mobile_mp3',
            'http://ic2.101.ru:8000/v4_1',
            'http://online.radiorecord.ru:8101/rr_320',
            'http://air.radiorecord.ru:8102/sd90_320',
            'http://46.105.180.202:8040/sr_128',
            'http://strm112.1.fm/chilloutlounge_mobile_mp3',
            'http://185.53.169.128:8000/192',
            'http://sumerki.su:8000/Sumerki',
            'http://myradio.ua:8000/loungefm128.mp3',
            'http://icecast.piktv.cdnvideo.ru/vanya',  #:8108/shanson128.mp3
            'http://icecast.rmg.cdnvideo.ru/rr.mp3',  #:8000/russianradio128.mp3
            'http://81.30.54.74:8000/radio4',
            'http://ic2.101.ru:8000/v5_1',
            'http://radio.globaltranceinvasion.com:8000/radiohi',
            'http://icecast.vgtrk.cdnvideo.ru/mayakfm_mp3_192kbps',
            'http://nashe1.hostingradio.ru/nashe-128.mp3',
            'http://icecast.radiodfm.cdnvideo.ru/dfm.mp3',
            'http://ic2.101.ru:8000/v1_1',
            'http://listen1.myradio24.com:9000/4455',
            'http://174.36.206.197:8000/;stream.nsv',
            'http://choco.hostingradio.ru:10010/fm', #http://pianosolo.streamguys.net:80/live
            'http://sc1c-sjc.1.fm:7070/?type=.flv',
            'http://source.dnbradio.com:10128/128k.mp3',
            'http://sc3b-sjc.1.fm:7802/?type=.flv',
            'http://quarrel.str3am.com:7990/;stream.nsv&type=mp3',
            'http://s7.radioheart.ru:8003/live',
            'http://stream.dubstep.fm/stream/1/',
            'http://176.104.22.115:8000/192.mp3',
    ]
names = [   'Вести',       'Амстердам транс',
            'Романтика',   'Рекорд электроника', 
            '90-е гг',     'Электроскай', 
            '1фм лаунж',   'Атмосфера ланж', 
            'Сумерьки',    'ЛанжФМ', 
            'Ваня',        'Русское Радио', 
            'Дача',        'Юмор фм', 
            'Транс',       'Маяк', 
            'Наше радио',  'Электроника', 
            'Энергия',     'Хип Хоп', 
            'Классика',    'Шакалад', 
            'Классика',    'ДНБ', 
            'Кантри',      'Жаз', 
            '80-е гг',     'Дабстеп', 
            'Прогрессивное','custom link...',
    ]

def dolist(urls,names):
    for u,n in zip(urls,names):
        radiola.rp_playlist.add()
        radiola.rp_playlist[-1].url = u
        radiola.rp_playlist[-1].name = n

classes = (
    RP_Playlist,
    SV_OT_radiola,
    SV_PT_radiola_panel
)

register, unregister = bpy.utils.register_classes_factory(classes)

rp_playlist: bpy.props.CollectionProperty(type=RP_Playlist)
radiola_clear: bpy.props.BoolProperty(default=False)
radiola: bpy.props.IntProperty()
radiola_ind: bpy.props.IntProperty()

@nortikin
Copy link
Owner

nortikin commented Nov 1, 2018

File "//\blender\radiola_2.8.blend\radiola.py", line 85, in draw
AttributeError: module 'radiola' has no attribute 'radiola_clear'

if __name__ == '__main__':
    register()

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 2, 2018

i'm starting the 2.8 port now. i need distraction or something :)

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 2, 2018

lol.. where is nodeview in 2.8 now ? :)

@nortikin
Copy link
Owner

nortikin commented Nov 3, 2018

that is a question... How AN deal?

@nortikin
Copy link
Owner

nortikin commented Nov 3, 2018

https://devtalk.blender.org/t/custom-node-trees/1614
custom node template in 2.8

@nortikin
Copy link
Owner

nortikin commented Nov 3, 2018

python nodetree demo

import bpy
from bpy.types import NodeTree, Node, NodeSocket

# Implementation of custom nodes from Python


# Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.
class MyCustomTree(NodeTree):
    # Description string
    '''A custom node tree type that will show up in the node editor header'''
    # Optional identifier string. If not explicitly defined, the python class name is used.
    bl_idname = 'CustomTreeType'
    # Label for nice name display
    bl_label = "Custom Node Tree"
    # Icon identifier
    bl_icon = 'NODETREE'


# Custom socket type
class MyCustomSocket(NodeSocket):
    # Description string
    '''Custom node socket type'''
    # Optional identifier string. If not explicitly defined, the python class name is used.
    bl_idname = 'CustomSocketType'
    # Label for nice name display
    bl_label = "Custom Node Socket"

    # Enum items list
    my_items = (
        ('DOWN', "Down", "Where your feet are"),
        ('UP', "Up", "Where your head should be"),
        ('LEFT', "Left", "Not right"),
        ('RIGHT', "Right", "Not left")
    )

    my_enum_prop = bpy.props.EnumProperty(name="Direction", description="Just an example", items=my_items, default='UP')

    # Optional function for drawing the socket input value
    def draw(self, context, layout, node, text):
        if self.is_output or self.is_linked:
            layout.label(text)
        else:
            layout.prop(self, "my_enum_prop", text=text)

    # Socket color
    def draw_color(self, context, node):
        return (1.0, 0.4, 0.216, 0.5)


# Mix-in class for all custom nodes in this tree type.
# Defines a poll function to enable instantiation.
class MyCustomTreeNode:
    @classmethod
    def poll(cls, ntree):
        return ntree.bl_idname == 'CustomTreeType'


# Derived from the Node base type.
class MyCustomNode(Node, MyCustomTreeNode):
    # === Basics ===
    # Description string
    '''A custom node'''
    # Optional identifier string. If not explicitly defined, the python class name is used.
    bl_idname = 'CustomNodeType'
    # Label for nice name display
    bl_label = "Custom Node"
    # Icon identifier
    bl_icon = 'SOUND'

    # === Custom Properties ===
    # These work just like custom properties in ID data blocks
    # Extensive information can be found under
    # http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties
    my_string_prop = bpy.props.StringProperty()
    my_float_prop = bpy.props.FloatProperty(default=3.1415926)

    # === Optional Functions ===
    # Initialization function, called when a new node is created.
    # This is the most common place to create the sockets for a node, as shown below.
    # NOTE: this is not the same as the standard __init__ function in Python, which is
    #       a purely internal Python method and unknown to the node system!
    def init(self, context):
        self.inputs.new('CustomSocketType', "Hello")
        self.inputs.new('NodeSocketFloat', "World")
        self.inputs.new('NodeSocketVector', "!")

        self.outputs.new('NodeSocketColor', "How")
        self.outputs.new('NodeSocketColor', "are")
        self.outputs.new('NodeSocketFloat', "you")

    # Copy function to initialize a copied node from an existing one.
    def copy(self, node):
        print("Copying from node ", node)

    # Free function to clean up on removal.
    def free(self):
        print("Removing node ", self, ", Goodbye!")

    # Additional buttons displayed on the node.
    def draw_buttons(self, context, layout):
        layout.label("Node settings")
        layout.prop(self, "my_float_prop")

    # Detail buttons in the sidebar.
    # If this function is not defined, the draw_buttons function is used instead
    def draw_buttons_ext(self, context, layout):
        layout.prop(self, "my_float_prop")
        # my_string_prop button will only be visible in the sidebar
        layout.prop(self, "my_string_prop")

    # Optional: custom label
    # Explicit user label overrides this, but here we can define a label dynamically
    def draw_label(self):
        return "I am a custom node"


### Node Categories ###
# Node categories are a python system for automatically
# extending the Add menu, toolbar panels and search operator.
# For more examples see release/scripts/startup/nodeitems_builtins.py

import nodeitems_utils
from nodeitems_utils import NodeCategory, NodeItem

# our own base class with an appropriate poll function,
# so the categories only show up in our own tree type
class MyNodeCategory(NodeCategory):
    @classmethod
    def poll(cls, context):
        return context.space_data.tree_type == 'CustomTreeType'


# all categories in a list
node_categories = [
    # identifier, label, items list
    MyNodeCategory('SOMENODES', "Some Nodes", items=[
        # our basic node
        NodeItem("CustomNodeType"),
    ]),
    MyNodeCategory('OTHERNODES', "Other Nodes", items=[
        # the node item can have additional settings,
        # which are applied to new nodes
        # NB: settings values are stored as string expressions,
        # for this reason they should be converted to strings using repr()
        NodeItem("CustomNodeType", label="Node A", settings={
            "my_string_prop": repr("Lorem ipsum dolor sit amet"),
            "my_float_prop": repr(1.0),
        }),
        NodeItem("CustomNodeType", label="Node B", settings={
            "my_string_prop": repr("consectetur adipisicing elit"),
            "my_float_prop": repr(2.0),
        }),
    ]),
]

classes = (
    MyCustomTree,
    MyCustomSocket,
    MyCustomNode,
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories)


def unregister():
    nodeitems_utils.unregister_node_categories('CUSTOM_NODES')

    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)


if __name__ == "__main__":
    register()

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 3, 2018

it's already partially working, it was a lot of work... adding the viewers back today (new versions of existing viewer/objects nodes)

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 3, 2018

image

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 3, 2018

current status is here in this pullrequest: #2299

@zeffii zeffii added this to threads in 2.8 threads Nov 5, 2018
@Durman
Copy link
Collaborator

Durman commented Nov 22, 2018

Alt text

@Durman
Copy link
Collaborator

Durman commented Nov 24, 2018

Can be useful.
Alt text

@zeffii
Copy link
Collaborator Author

zeffii commented Nov 27, 2018

closing this because i dont want to have todolists in two places for the same project

@zeffii zeffii closed this as completed Nov 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Development

No branches or pull requests

8 participants