2
$\begingroup$

i'm writing some scripts for Blender in the context my masterthesis. I want to create a new screen by my script. The layout of the screen should be defined by the script, too. There i've the problem, that i've graphical errors like shown in the following image:

enter image description here

The type of the area changes as you can see on the icon. But the user interface stays at a wrong type. This is the actual code to create this layout:

import bpy

class NewEmptyScreenOperator(bpy.types.Operator):
    bl_idname = "wm.new_empty_screen"
    bl_label = "New Empty Screen Operator"

    def __new_screen(self):
        old = bpy.data.screens.items()
        bpy.ops.screen.new()
        new = bpy.data.screens.items()

        for i in new:
            if not i in old:
                return i


    def __delete_areas(self, override):
        areas = []
        for i in override['screen'].areas:
            areas.append([i.x, i.y, i.width, i.height])

        def delete_area():
            for i in range(0, len(areas)):
                for j in range(0, len(areas)):
                    #identisch → auslassen
                    if i == j:
                        continue

                    if areas[i][0] == areas[j][0] and areas[i][2] == \
                        areas[j][2]:
                        #über
                        if areas[i][1] + areas[i][3] + 1 == areas[j][1]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[i][0]+1, min_y = areas[i][1], max_x = \
                                areas[j][0]+1,  max_y = areas[j][1]+1)
                            areas[i][3] = areas[i][3] + areas[j][3] + 1
                            del areas[j]
                            return
                        #unter
                        if areas[j][1] + areas[j][3] + 1 == areas[i][1]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[j][0]+1, min_y = areas[j][1], max_x = \
                                areas[i][0]+1,  max_y = areas[i][1]+1)
                            areas[j][3] = areas[j][3] + areas[i][3] + 1
                            del areas[i]
                            return

                    if areas[i][1] == areas[j][1] and areas[i][3] == \
                        areas[j][3]:
                        #rechts
                        if areas[i][0] + areas[i][2] + 1 == areas[j][0]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[i][0]+1, min_y = areas[i][1], max_x = \
                                areas[j][0]+1,  max_y = areas[j][1]+1)
                            areas[i][2] = areas[i][2] + areas[j][2] + 1
                            del areas[j]
                            return
                        #links
                        if areas[j][0] + areas[j][2] + 1 == areas[i][0]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[j][0]+1, min_y = areas[j][1], max_x = \
                                areas[i][0]+1,  max_y = areas[i][1]+1)
                            areas[j][2] = areas[j][2] + areas[i][2] + 1
                            del areas[i]
                            return

        while len(areas)>1:
            delete_area()        


    def __rename_screen(self, screen, new_name):
        if(not self.__screen_existing(new_name)):
            screen.name = new_name
        else:
            i = 1
            while(self.__screen_existing(new_name + ".%03i" % i)):
                i += 1
            screen.name = new_name + ".%03i" % i

    def __screen_existing(self, name):
        for i in bpy.data.screens:
            if(i.name == name):
                return True
        return False


    def __set_areas(self, override):
        override['area']       = override['screen'].areas[0]
        override['region']     = override['screen'].areas[0].regions[0]
        override['space_data'] = override['screen'].areas[0].spaces [0]

        bpy.ops.screen.area_split(override, direction='HORIZONTAL', \
            factor=0.99)
        override['screen'].areas[1].type = 'INFO'
        override['screen'].areas[0].type = 'VIEW_3D'

        bpy.ops.screen.area_split(override, direction='VERTICAL', factor=0.8)
        override['screen'].areas[2].type = 'OUTLINER'


    def execute(self, context):
        self.__old_screen_name = bpy.context.screen.name

        new = self.__new_screen()

        override = bpy.context.copy()
        override['screen'] = new[1]

        self.__delete_areas(override)
        self.__rename_screen(override['screen'], "Simple")
        self.__set_areas(override)

        return {'FINISHED'}

    def invoke(self, context, event):
        self.execute(context)
        return {'FINISHED'}

#test call
#bpy.ops.wm.new_empty_screen()
#bpy.ops.wm.new_empty_screen('INVOKE_DEFAULT')

def register():
    bpy.utils.register_module(__name__)

if __name__ == "__main__":
    register()

If I'm using the procedure __set_areas(self, override) seperately the error doesn't happens. This can be done manually or by a timer (what's more a workaround than a solution). How can I solve the problem without using a timer?

Thanks

$\endgroup$

1 Answer 1

0
$\begingroup$

It seams to be impossible to add areas after deleting some without running in graphical errors like shown in my initial post. So now i'll tell you my best workaround:

import bpy

class NewEmptyScreenOperator(bpy.types.Operator):
    bl_idname = "wm.new_empty_screen"
    bl_label = "New Empty Screen Operator"
    __timer = None

    def __new_screen(self):
        old = bpy.data.screens.items()
        bpy.ops.screen.new()
        new = bpy.data.screens.items()

        for i in new:
            if not i in old:
                return i


    def __delete_areas(self, override):
        areas = []
        for i in override['screen'].areas:
            areas.append([i.x, i.y, i.width, i.height])

        def delete_area():
            for i in range(0, len(areas)):
                for j in range(0, len(areas)):
                    #identisch → auslassen
                    if i == j:
                        continue

                    if areas[i][0] == areas[j][0] and areas[i][2] == \
                        areas[j][2]:
                        #über
                        if areas[i][1] + areas[i][3] + 1 == areas[j][1]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[i][0]+1, min_y = areas[i][1], max_x = \
                                areas[j][0]+1,  max_y = areas[j][1]+1)
                            areas[i][3] = areas[i][3] + areas[j][3] + 1
                            del areas[j]
                            return
                        #unter
                        if areas[j][1] + areas[j][3] + 1 == areas[i][1]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[j][0]+1, min_y = areas[j][1], max_x = \
                                areas[i][0]+1,  max_y = areas[i][1]+1)
                            areas[j][3] = areas[j][3] + areas[i][3] + 1
                            del areas[i]
                            return

                    if areas[i][1] == areas[j][1] and areas[i][3] == \
                        areas[j][3]:
                        #rechts
                        if areas[i][0] + areas[i][2] + 1 == areas[j][0]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[i][0]+1, min_y = areas[i][1], max_x = \
                                areas[j][0]+1,  max_y = areas[j][1]+1)
                            areas[i][2] = areas[i][2] + areas[j][2] + 1
                            del areas[j]
                            return
                        #links
                        if areas[j][0] + areas[j][2] + 1 == areas[i][0]:
                            bpy.ops.screen.area_join(override, min_x = \
                                areas[j][0]+1, min_y = areas[j][1], max_x = \
                                areas[i][0]+1,  max_y = areas[i][1]+1)
                            areas[j][2] = areas[j][2] + areas[i][2] + 1
                            del areas[i]
                            return

        while len(areas)>1:
            delete_area()        


    def __rename_screen(self, screen, new_name):
        if(not self.__screen_existing(new_name)):
            screen.name = new_name
        else:
            i = 1
            while(self.__screen_existing(new_name + ".%03i" % i)):
                i += 1
            screen.name = new_name + ".%03i" % i

    def __screen_existing(self, name):
        for i in bpy.data.screens:
            if(i.name == name):
                return True
        return False


    def __set_areas(self, override):
        override['area']       = override['screen'].areas[0]
        override['region']     = override['screen'].areas[0].regions[0]
        override['space_data'] = override['screen'].areas[0].spaces [0]

        bpy.ops.screen.area_split(override, direction='HORIZONTAL', \
            factor=0.99)
        override['screen'].areas[1].type = 'INFO'
        override['screen'].areas[0].type = 'VIEW_3D'

        bpy.ops.screen.area_split(override, direction='VERTICAL', factor=0.8)
        override['screen'].areas[2].type = 'OUTLINER'


    def execute(self, context):
        self.__old_screen_name = bpy.context.screen.name

        new = self.__new_screen()

        override = bpy.context.copy()
        override['screen'] = new[1]

        self.__delete_areas(override)
        self.__rename_screen(override['screen'], "Simple")
        #self.__set_areas(override)

        self.__timer = context.window_manager.event_timer_add(0.1, \
            context.window)
        context.window_manager.modal_handler_add(self)

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        self.execute(context)
        return {'RUNNING_MODAL'}

    def modal(self, context, event):
        if event.type == 'TIMER':
            self.__set_areas(bpy.context.copy())
            bpy.context.window_manager.event_timer_remove(self.__timer)
            return {'FINISHED'}

        return {'PASS_THROUGH'}

#test call
#bpy.ops.wm.new_empty_screen()
#bpy.ops.wm.new_empty_screen('INVOKE_DEFAULT')

def register():
    bpy.utils.register_module(__name__)

if __name__ == "__main__":
    register()
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .