Esempio n. 1
0
class chatPage(MDGridLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols = 1
        self.rows = 2

        self.history = Scrolllabel(height=Window.size[1] * 0.9,
                                   size_hint_y=None)
        self.add_widget(self.history)

        self.new_message = TextInput(width=Window.size[0] * 0.8,
                                     size_hint_x=None,
                                     multiline=False)
        self.send = Button(text="Send")
        self.send.bind(on_press=self.send_message)

        self.bottom_line = MDGridLayout(cols=2)
        self.bottom_line.add_widget(self.new_message)
        self.bottom_line.add_widget(self.send)

        self.add_widget(self.bottom_line)

        Window.bind(on_key_down=self.on_key_down)

        Clock.schedule_once(self.focus_text_input, 1)
        client.start_listening(self.incoming_message, show_err)

    def on_key_down(self, instance, keyboard, keycode, text, modifiers):
        if keycode == 40:
            self.send_message(None)

    def send_message(self, _):

        message = self.new_message.text

        self.new_message.text = ''
        if message:
            self.history.update_chat_history(
                f"[color=E98567]{kivymdMDApp.connect_page.username.text}[/color] [color=ffffff]> {str(message)}[/color]"
            )
            client.send(message)

        Clock.schedule_once(self.focus_text_input, 0.1)

    def focus_text_input(self, _):
        self.new_message.focus = True

    def incoming_message(self, username, message):
        self.history.update_chat_history(
            f"[color=5E97AF]{username}[/color][color=ffffff]> {str(message)}[/color]"
        )
Esempio n. 2
0
    def create_top_card_layout(self, num_of_exc, num_of_exc_total, exc):
        help_layout = MDGridLayout(rows=1, cols=2)
        excnum = str(num_of_exc + 1) + " of " + str(num_of_exc_total)
        exc_num = MDLabel(text=excnum,
                          font_style="Caption",
                          theme_text_color="Secondary",
                          pos_hint={
                              "center_y": 0.85,
                              "center_x": 0.2
                          })
        deleteBox = MDCheckbox(pos_hint={
            "center_y": 0.85,
            "center_x": 0.9275
        },
                               on_release=self.active_card_check_box)
        self.ex_reference_by_checkBox[deleteBox] = exc
        help_layout.add_widget(exc_num)
        help_layout.add_widget(deleteBox)

        return help_layout, deleteBox
Esempio n. 3
0
class Scrolllabel(ScrollView):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.layout = MDGridLayout(cols=1, size_hint_y=None)
        self.add_widget(self.layout)

        self.chat_history = MDLabel(size_hint_y=None, markup=True)
        self.scroll_to_point = MDLabel()

        self.layout.add_widget(self.chat_history)
        self.layout.add_widget(self.scroll_to_point)

        self.scroll_to(self.scroll_to_point)

    def update_chat_history(self, message, _=None):
        self.chat_history.text += '\n' + str(message)

        self.layout.height = self.chat_history.texture_size[1] + 20
        print(self.chat_history.texture_size[1])
        self.chat_history.height = self.chat_history.texture_size[1]
        self.chat_history.text_size = (self.chat_history.width * 0.98, None)
Esempio n. 4
0
    def new_top(self, color=None):
        if color is None:
            color = [131 / 255, 223 / 255, 25 / 255, .9]
        new_top = MDGridLayout(
            cols=4,
            size_hint=(None, None),
            center_x=1,
            width=600,
            height=70
        )
        new_top.md_bg_color = [200 / 255, 200 / 255, 200 / 255, .7]

        if len(self.radio_play_id) == 0:
            return new_top

        new_top.add_widget(AsyncImage(
            source=self.radio_play_id[5]
        ))

        new_top.add_widget(MDLabel(
            text="%s " % self.radio_play_id[1],
            theme_text_color="Custom",
            halign="right",
            text_color=[223 / 255, 102 / 255, 0, 1],
            font_style="H5",
        )
        )
        new_top.add_widget(MDIconButton(
            icon="record",
            user_font_size="48sp",
            theme_text_color="Custom",
            text_color=color,
            on_press=self.start_record)
        )
        new_top.add_widget(MDIconButton(
            icon="stop",
            user_font_size="48sp",
            theme_text_color="Custom",
            on_press=self.stop_record)
        )
        return new_top
Esempio n. 5
0
    def build(self):

        # AC Card
        self.ac_card = AcCard((0.5, 0.5))
        self.add_widget(self.ac_card)

        # all the features for ac
        features_layout = MDGridLayout()
        features_layout.cols = 2

        # Temp incease, decrease
        new_box_layout = MDFloatLayout()
        dec_button = Buttonn('temp-', colors['cold_color'])
        new_box_layout.add_widget(dec_button)
        dec_button.on_press = partial(self.ac_features_send, dec_button)
        features_layout.add_widget(new_box_layout)

        new_box_layout = MDFloatLayout()
        inc_button = MDCard(
            orientation='vertical',
            padding='10dp',
            pos_hint={
                'center_x': 0.5,
                'center_y': 0.5
            },
            size_hint=(0.75, 0.75),
        )
        inc_button.md_bg_color = ['warm_color']
        inc_button.add_widget(MDLabel(text='Temp+'))
        inc_button.id = 'temp+'
        inc_button.on_press = partial(self.ac_features_send, inc_button)
        new_box_layout.add_widget(inc_button)
        features_layout.add_widget(new_box_layout)

        features_layout.add_widget(btn(text='TODO'))
        features_layout.add_widget(btn(text='TODO'))
        features_layout.add_widget(btn(text='TODO'))
        features_layout.add_widget(btn(text='TODO'))

        self.add_widget(features_layout)
Esempio n. 6
0
 def create_numeric_control(self, app, text=''):
     grid = MDGridLayout(spacing=3, padding=3, cols=3)
     decrease_number_btn = MDFloatingActionButton(
         icon="minus",
         md_bg_color=app.theme_cls.primary_color,
         on_release=self.numeric_decrement)
     self.parameter_label = LabelButton(
         text=text,
         font_size=40,
         halign='center',
         theme_text_color="Custom",
         text_color=(1, .2, 1, 1),
         on_release=self.commit_parameter_value)
     increase_number_btn = MDFloatingActionButton(
         icon="plus",
         md_bg_color=app.theme_cls.primary_color,
         on_release=self.numeric_increment)
     self.popup_container.clear_widgets()
     grid.add_widget(decrease_number_btn)
     grid.add_widget(self.parameter_label)
     grid.add_widget(increase_number_btn)
     self.popup_container.add_widget(grid)
Esempio n. 7
0
    def create_switch_control(self, text, app):
        self.switch_state = True if text == 'ON' else False
        grid = MDGridLayout(spacing=3, padding=3, cols=3)
        self.switch = MySwitch(width=dp(64), active=self.switch_state)
        self.switch.bind(on_press=self.switch_callback)

        self.parameter_label = LabelButton(
            text=text,
            font_size=40,
            halign='center',
            theme_text_color="Custom",
            text_color=(1, 0, 0, 1) if not self.switch.active else
            (0, 1, 0, 1),
            on_release=self.commit_parameter_value)
        commit_btn = MDRoundFlatIconButton(
            text="Commit",
            md_bg_color=app.theme_cls.primary_color,
            on_release=self.commit_parameter_value)
        self.popup_container.clear_widgets()
        grid.add_widget(self.parameter_label)
        grid.add_widget(self.switch)
        grid.add_widget(commit_btn)
        self.popup_container.add_widget(grid)
Esempio n. 8
0
class Show(MDList):
    app = Zdrowie()
    NORMAL = 4
    EXTENDED = 16

    def __init__(self, **kwargs):
        super(Show, self).__init__(**kwargs)
        self.numbers = self.pickle_list()[3]
        self.countries = []
        self.container = None
        self.prov_item = None
        self.delete_container = None
        for self.key, self.value in self.numbers.items():
            icon = IconLeftWidget(icon=f'images/countries/{self.key}.png',
                                  size_hint=(0.9, 0.9))
            self.item = CountryOneLineIconListItem(text=str(self.key))
            self.add_widget(self.item)
            self.item.add_widget(icon)

    def down_button(self, country, *args):
        try:
            self.clear_screen()
        except:
            pass
        self.phone_number_screen_manager.current = 'phone_number_list'
        numbers = self.pickle_list()[3][country]
        if len(numbers) == self.NORMAL:
            names = self.pickle_list()[0]
            self.container = SecondScreen()
            self.phone_container.add_widget(self.container)
            for i in range(self.NORMAL):
                self.container.add_widget(
                    MDExpansionPanel(
                        icon=f'images/emergency/{names[i]}.png',
                        content=PhoneContent(numbers[i]),
                        panel_cls=MDExpansionPanelOneLine(text=names[i])))

        elif len(numbers) == self.EXTENDED:
            names = self.pickle_list()[1]
            self.container = SecondScreen()
            self.phone_container.add_widget(self.container)
            self.prov_item = OneLineAvatarIconListItem(
                text='Numery ws. koronawirusa w Województwach',
                on_release=self.clear_add_provinces)
            prov_item_icon_left = IconLeftWidget(
                icon='images/emergency/mask.png', size_hint=(0.9, 0.9))
            prov_item_icon_right = IconRightWidget(icon='arrow-right')
            self.phone_list_container.add_widget(self.prov_item)
            self.prov_item.add_widget(prov_item_icon_left)
            self.prov_item.add_widget(prov_item_icon_right)
            for i in range(self.EXTENDED):
                self.container.add_widget(
                    MDExpansionPanel(
                        icon=f'images/emergency/{names[i]}.png',
                        content=PhoneContent(numbers[i]),
                        panel_cls=MDExpansionPanelOneLine(text=names[i])))

    def provinces_list(self, *args):
        self.phone_number_screen_manager.current = 'phone_provinces'
        content = self.pickle_list()[4]
        self.delete_container = MDGridLayout(cols=1, adaptive_height=True)
        self.phone_provinces.add_widget(self.delete_container)
        for key, value in content.items():
            item = MDExpansionPanel(
                icon=f'images/provinces/{key}.png',
                content=ProvinceContent(content[key]),
                panel_cls=MDExpansionPanelOneLine(text=key))

            self.delete_container.add_widget(item)

    def pickle_list(self):
        load = []
        if self.app.language == 'pl':
            file = 'countries_data.dat'
        else:
            file = 'countries_data_eng.dat'

        with open(file, 'rb') as file:
            a = pickle.load(file)
            load.append(a)
            b = pickle.load(file)
            load.append(b)
            c = pickle.load(file)
            load.append(c)
            d = pickle.load(file)
            load.append(d)
            e = pickle.load(file)
            load.append(e)
            return load

    def clear_add_provinces(self, *args):
        self.clear_provinces()
        self.provinces_list()

    def clear_screen(self):
        self.phone_container.remove_widget(self.container)

    def clear_provinces(self):
        try:
            self.phone_list_container.remove_widget(self.prov_item)
        except:
            pass
        try:
            self.phone_provinces.remove_widget(self.delete_container)
        except:
            pass
Esempio n. 9
0
class ConnectionPage(MDGridLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols = 1
        self.space = "             "

        if isfile("creds.info"):
            with open("creds.info", "r") as f:
                creds = f.read().split(",")
                prev_ip = creds[0]
                prev_port = creds[1]
                prev_username = creds[2]
        else:
            prev_ip = ""
            prev_port = ""
            prev_username = ""

        self.credit = MDGridLayout(cols=2,
                                   height=Window.size[1] * 0.8,
                                   size_hint_y=None)
        self.add_widget(self.credit)

        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))
        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))

        self.credit.add_widget(
            MDLabel(text=f"{self.space}[color=ffffff]ip:[/color]",
                    markup=True))
        self.ip = MDTextField(text=prev_ip, multiline=False)
        self.credit.add_widget(self.ip)

        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))
        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))

        self.credit.add_widget(
            MDLabel(text=f"{self.space}[color=ffffff]port:[/color]",
                    markup=True))
        self.port = MDTextField(text=prev_port, multiline=False)
        self.credit.add_widget(self.port)

        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))
        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))

        self.credit.add_widget(
            MDLabel(text=f"{self.space}[color=ffffff]username:[/color]",
                    markup=True))
        self.username = MDTextField(text=prev_username, multiline=False)
        self.credit.add_widget(self.username)

        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))
        self.credit.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.07, size_hint_y=None))

        self.connect = Button(text="connect")
        self.connect.bind(on_press=self.connction)
        self.add_widget(self.connect)

        self.add_widget(
            MDLabel(text="", height=Window.size[1] * 0.02, size_hint_y=None))

    def connction(self, instance):
        ip = self.ip.text
        port = self.port.text
        username = self.username.text

        with open("creds.info", "w") as f:
            f.write(f"{ip},{port},{username}")

        info = f"[color=ffffff]{ip}:{port} connected as {username}[/color]"
        kivymdMDApp.info_page.updateInfo(info)

        kivymdMDApp.screenmanager.current = "info"
        Clock.schedule_once(self.connectchat, 1)

    def connectchat(self, _):
        ip = self.ip.text
        port = int(self.port.text)
        username = self.username.text
        if not client.connect(ip, port, username, show_err):
            return

        kivymdMDApp.create_chatpage()
        kivymdMDApp.screenmanager.current = "chat"
Esempio n. 10
0
class MainScreen(Screen):
    """
    This class is representing the Main window of the app,
    is has a child widget of the KivyCamera which is runs the camera for
    capturing the video
    """
    def __init__(self, scrn_mngr, **kwargs):
        super(MainScreen, self).__init__(**kwargs)
        self.grid = MDGridLayout()
        self.grid.cols = 1
        self.practice_type = None
        self.vs = None
        self.rep_num = 0
        # self.manager.transition.direction = 'right'
        self.scrn_mngr = scrn_mngr
        self.scrn_mngr.transition.direction = 'right'

        self.toolbar = MDToolbar()
        self.set_tool_bar_params()
        self.grid.add_widget(self.toolbar)

        # ''' Create the camera view'''
        self.cam = None
        # self.grid.add_widget(self.cam)

        # self.create_camera()

        # ''' Set the back button'''
        # self.set_back_btn()

        self.add_widget(self.grid)

    def set_tool_bar_params(self):
        """
        This function is creating the toolbar of the Main screen to be similar as the Welcome screen
        """
        self.toolbar.title = "Fit Aware"
        self.toolbar.type = "top"
        self.toolbar.anchor_title = 'center'
        self.toolbar.left_action_items = [[
            "keyboard-backspace", lambda x: self.parent.move_to_page("else")
        ]]
        self.toolbar.elevation = 10

    def create_camera(self):
        """
        This function is creating the OpenCV camera
        with the video capturing and creates the
        KivyCamera child of the Main Screen
        """
        self.vs = cv2.VideoCapture(0)
        ap = argparse.ArgumentParser()
        ap.add_argument("-v", "--video", help="path to the video file")
        ap.add_argument("-a",
                        "--min-area",
                        type=int,
                        default=500,
                        help="minimum area size")

        args = vars(ap.parse_args())
        if self.cam in self.grid.children:
            self.grid.remove_widget(self.cam)
        self.cam = KivyCamera(capture=self.vs,
                              fps=1000000,
                              args=args,
                              pr_type=self.practice_type,
                              prnt=self)
        self.grid.add_widget(self.cam)
        # self.cam.started = True

    def close(self):
        """
        This function is closing the Main Screen
        by stopping the Queue thread
        """
        if self.practice_type:
            self.practice_type.q.stop()
Esempio n. 11
0
class MainLayout(MDGridLayout):

    def __init__(self, **kwargs):
        super(MainLayout, self).__init__(**kwargs)
        self.data_tables = MDDataTable(
            padding=10,
            size_hint=(None, None),
            center_x=1,
            width=600,
            height=680,
            use_pagination=True,
            rows_num=10,
            column_data=[
                ("#", dp(5)),
                ("Name", dp(50)),
                ("Genre", dp(30)),
                ("Country", dp(20)),
            ],
            row_data=[
                [
                    i[0],
                    ("play", [39 / 256, 174 / 256, 96 / 256, 1], i[1]),
                    i[2],
                    i[3]
                ] for i in radio_list()]
        )
        self.radio_play_id = []
        self.record = False
        self.cols = 1
        self.topWindow = MDGridLayout(cols=1, adaptive_height=True)
        self.topWindow.add_widget(self.new_top())
        self.add_widget(self.topWindow)
        self.table()

    def table(self):
        self.add_widget(self.data_tables)
        self.data_tables.bind(on_row_press=self.play_radio)

    def new_top(self, color=None):
        if color is None:
            color = [131 / 255, 223 / 255, 25 / 255, .9]
        new_top = MDGridLayout(
            cols=4,
            size_hint=(None, None),
            center_x=1,
            width=600,
            height=70
        )
        new_top.md_bg_color = [200 / 255, 200 / 255, 200 / 255, .7]

        if len(self.radio_play_id) == 0:
            return new_top

        new_top.add_widget(AsyncImage(
            source=self.radio_play_id[5]
        ))

        new_top.add_widget(MDLabel(
            text="%s " % self.radio_play_id[1],
            theme_text_color="Custom",
            halign="right",
            text_color=[223 / 255, 102 / 255, 0, 1],
            font_style="H5",
        )
        )
        new_top.add_widget(MDIconButton(
            icon="record",
            user_font_size="48sp",
            theme_text_color="Custom",
            text_color=color,
            on_press=self.start_record)
        )
        new_top.add_widget(MDIconButton(
            icon="stop",
            user_font_size="48sp",
            theme_text_color="Custom",
            on_press=self.stop_record)
        )
        return new_top

    def play_radio(self, obj, obj2):

        if obj2.text in [i[1] for i in radio_list()]:
            self.radio_play_id = [i for i in radio_list() if i[1] == obj2.text][0]

            self.radio = Radio(self.radio_play_id[4], self.radio_play_id[1])
            try:
                self.radio.radio_start()
            except:
                return
            self.topWindow.clear_widgets()
            self.topWindow.add_widget(self.new_top())

    def start_record(self, obj):
        if len(self.radio_play_id) > 0:
            self.topWindow.clear_widgets()
            self.topWindow.add_widget(self.new_top([1, 0, 0, 1]))
            self.radio = Radio(self.radio_play_id[4], self.radio_play_id[1], record=True)
            self.radio.radio_start()
            self.record = True

    def stop_record(self, obj):
        if self.record:
            self.topWindow.clear_widgets()
            self.topWindow.add_widget(self.new_top())
            self.record = False
        self.radio.radio_stop()

    def close_popup(self, obj):
        self.popup.dismiss()

    def update_table(self):
        self.data_tables.clear_widgets()
        self.remove_widget(self.grid)
        self.table()
Esempio n. 12
0
class MangaCoverContainer(ScrollView):
    def __init__(self, master, **kwargs):
        super().__init__(**kwargs)
        self.master = master
        self.manga_data = self.master.manga_data
        self.downloader_links_methods = {
            "manganelo": MangaNelo.download_manga,
            "kissmanga": KissManga.download_manga,
            "rawdevart": RawDevArt.download_manga,
            "senmanga": SenManga.download_manga
        }
        self.effect_cls = "ScrollEffect"
        self.bar_width = "10dp"
        self.pos_hint = {"top": .9}

        # This grid acts as a container for the number of manga found and the table with the clickable tiles
        self.outer_gird = MDGridLayout(rows=2,
                                       adaptive_height=True,
                                       padding=("0dp", "20dp", "0dp", "20dp"),
                                       pos_hint={"top": .8})
        self.outer_gird.add_widget(
            MDLabel(text=f"{len(self.manga_data)} manga were found",
                    halign="center",
                    pos_hint={
                        "center_x": .5,
                        "y": .9
                    }))

        # This grid acts a table to store all found manga
        self.grid = MDStackLayout(adaptive_height=True,
                                  orientation="lr-tb",
                                  spacing=("20dp", "20dp"),
                                  padding=("5dp", "30dp", "5dp", "30dp"))

        for title, links_tuple in self.manga_data.items():
            self.btn = MangaCoverTile(source=links_tuple[1],
                                      text=title,
                                      on_release=partial(
                                          self.make_request, title),
                                      size_hint=(.25, .25))
            self.grid.add_widget(self.btn)

        # Checks to see if any manga were found; An empty dict means no manga were found with the inputted text
        if self.manga_data == {}:
            self.grid.add_widget(
                MDLabel(text="No Manga found",
                        halign="center",
                        pos_hint={
                            "center_x": .5,
                            "center_y": .5
                        }))

        self.outer_gird.add_widget(self.grid)
        self.add_widget(self.outer_gird)

    # Note: the param tile acts as a button instance
    def make_request(self, title, tile):
        # Calls the appropriate downloader based on the selected site and starts a thread to prevent kivy event loop from locking
        download_thread_target = partial(
            self.downloader_links_methods.get(self.master.downloader), tile,
            title, self.manga_data.get(title))
        download_thread = Thread(name=f"Download Thread {title}",
                                 target=download_thread_target)

        # Flag used to ensure that the same manga is not downloaded while it is already being downloaded
        if self.master.download_threads.get(
                title, None
        ) == None:  # If a manga is already being downloaded it will not return None
            self.master.download_threads.update({title: download_thread})
            self.master.currently_downloading = True
            tile.progressbar.opacity = 1

            # Creates the directory for that manga within the manga root and changes to it
            create_manga_dirs(self.master.downloader, title)
            download_thread.start()
        else:
            display_message(f"{title} is already downloading")
Esempio n. 13
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.orientation = 'vertical'

        # Main screen layout
        screen_layout = MDGridLayout()
        screen_layout.cols = 2
        screen_layout.md_bg_color = [0, 1, 1, 1]

        # AC region
        self.timer = 0
        new_layout = MDFloatLayout()
        self.new_card = MDCard(
            orientation='vertical',
            padding='10dp',
            pos_hint={
                'center_x': 0.5,
                'center_y': 0.5
            },
            size_hint=(0.75, 0.75),
        )
        self.new_card.md_bg_color = app.off_red
        ac_image = Image(source='static/ac1.png', )
        ac_image.size_hint_y = 0.9

        ac_image.pos_hint = {'top': 1.0, 'center_x': 0.5}
        self.new_card.radius = [4] * 4

        # ac_button.bind(active=callback)
        self.new_card.add_widget(ac_image)
        self.new_card.on_press = self.ac_touch_down
        self.new_card.on_release = self.ac_touch_up
        temp = MDLabel(text='18ºC')
        temp.font_size = 10
        temp.size = (0.25, 1)
        temp.color = [1, 1, 1, 1]
        new_layout.add_widget(self.new_card)
        screen_layout.add_widget(new_layout)

        self.ac_popup = Popup(title='AC settings',
                              content=AcFeatures(),
                              size_hint=(0.75, 0.75))
        self.ac_popup.background_color = [i / 255
                                          for i in [137, 205, 211]] + [1]
        #self.ac_popup.on_open = self.faltu

        #--------------------------------------------------------------#

        # Light setup
        new_layout = MDFloatLayout()
        self.light_card = MDCard(
            orientation='horizontal',
            padding='10dp',
            pos_hint={
                'center_x': 0.5,
                'center_y': 0.5
            },
            size_hint=(0.75, 0.75),
        )
        self.light_card.md_bg_color = app.dark_color
        light_image = Image(
            source='static/light1.png',
            size_hint=(1, 1),
        )
        self.light_card.on_press = self.light_change
        self.light_card.add_widget(light_image)
        new_layout.add_widget(self.light_card)
        screen_layout.add_widget(new_layout)

        screen_layout.add_widget(Button(text='TODO'))
        screen_layout.add_widget(Button(text='TODO'))
        screen_layout.add_widget(Button(text='TODO'))
        screen_layout.add_widget(Button(text='TODO'))
        screen_layout.add_widget(Button(text='TODO'))
        screen_layout.add_widget(Button(text='TODO'))
        self.add_widget(screen_layout)