Glade

This topic was published by and viewed 2532 times since "". The last page revision was "".

Viewing 1 post (of 1 total)
  • Author
    Posts
  • DevynCJohnson
    DevynCJohnson
    Keymaster
    • Topics - 444
    • @devyncjohnson

    Glade is a popular WYSIWYG for GTK interfaces. Glade generates an XML file with the extension "*.glade". Developers can then use special bindings/libraries in their code that allows the program to load the GUI that is defined in the *.glade file. However, before application developers can get that far in their design, they need to understand Glade and the various widgets that can be placed on a window.

    Glade is the GUI designer for GTK2 and GTK3. GTK2 is no longer developed, but due to its stability and the large usage, many developers still use GTK2. Thus, Glade v3.8 is for GTK2. To create GTK3 windows, use the latest version of Glade (version 3.16 at the time of writing this article). Glade only offers tools for designing the GUI by placing graphical objects. In other words, there is no ability for coding. Instead, programmers design the window and then save the results to a file. Then, programmers open their preferred IDE and write code using the chosen language. In the code, use the command in the GTK binding for your language to import/load the XML code that defines the created window.

    glade-about-screen
    glade-about-screen

    For example, when I code, I open my preferred IDE (Geany) and write Python3 code. The language binding used by Python3 for GTK3 is PyGObject which is in the "gi.repository" module. Linux users can obtain this binding from the "python3-gi" package. So, after installing the binding, I import GTK by using "from gi.repository import Gtk". Then, to use my window, I use the "add_from_file()" command to add the contents of the specified *.glade file or "add_from_string()" if I copied the XML code into the Python script as a variable/constant.

    #!/usr/bin/env python3
    from gi.repository import Gtk
    gtkwindow = Gtk.Builder()
    gtkwindow.add_from_file('/path/to/glade/file.glade')
    # Some code to modify the window and provide the
    # desired functionality and such
    
    # Alternately,
    _GUI = (
    'XML code'
    'many lines'
    )
    from gi.repository import Gtk
    gtkwindow = Gtk.Builder()
    gtkwindow.add_from_string(buffer=_GUI)
    # "buffer=" in the parameter above fixes a minor Cxfreeze3 bug
    
    # Various code here

    Various languages may have a slightly different way of utilizing the language binding and loading the Glade code for the window. The GTK commands that manipulate the window or perform some GTK-related task are the same in all (or nearly all languages). However, the GTK command will use the syntax of your chosen language.

    Now, to explain the various tools and widgets in Glade. The interface is simple; by default, the widgets are on the left, the window is in the center, and the various tweaks and settings are on the right. In the "widget toolbox" (containing the available widgets) organizes the widgets into groups.

    • Actions – These widgets trigger an action like opening the help/about window.
    • Toplevels - This contains various windows. Some are ready-made windows like the "font chooser dialog", "color chooser dialog", etc. The "Application Window" widget is commonly used to design a custom window. Most developers will want to start with this widget.
    • Containers - After selecting a toplevel, containers are added to customize the window for various layouts and appearances. For example, if a scroll bar or tabs are desired, add them before adding buttons or text.
    • Control and Display - The labels (text), buttons, menus, etc. belong to this category.
    • GTK+ Unix Print Toplevels - These are toplevels (windows) specifically for printing.
    • Deprecated - Deprecated widgets are found here. Try not to use them since they are obsolete widgets.
    • Miscellaneous - Various widgets not belonging in other categories go here like Tree-view.
    • Composite - The widgets with more functionality and "sub-widgets" belong here like the font, file, and color choosers.
    glade-color
    glade-color

    NOTE: If you are using Glade3 (version 3.16 or above) and you do not have some of the widget categories that I have mentioned, then you must install some bindings and developer libraries. I have many developer libraries installed on my system, so I have more than a default installation would contain.

    glade-color-win
    glade-color-win

    To use Glade, first select a toplevel. Then, place the desired containers. Use the "box" and "grid" widgets to divide the window into multiple sections. If a scrollable window is desired, place a "scrolled window" widget on top of a "viewport" widget. Inside of the scrolled window widget, place the "textview" widget. Then, in your code, use the needed commands to load text into the "textview". The best way to better understand Glade and the widgets is to experiment with the various tools. Thankfully, clicking the "Preview Snapshot" allows developers to see a preview of their window.

    The "Properties Dock" allows developers to change the various attributes of widgets like size, appearance, etc. The "Signals" tab is useful for providing an interface between the GUI and the code. For instance, select a button that you wish to be the close button. Then, go to the "signals" tab and look for the signal named "clicked" under "GtkButton". For "Handler", type the name of the function (from your code) that will execute when the close button is clicked. Under "user data", select the name of the window (or other desired object). The selected object will be passed to the function. For example, the function can close the window by using the "destroy()" command and/or "Gtk.main_quit()".

    glade-close-btn
    glade-close-btn

    Passing data that is entered in a text box or the value of a check-box are passed to the programs code in a similar way. When configuring the signals of a button, type the name of the function under "Handler", and then (under "User data") select the menu, text-box, radio-button, etc. that will be passed to the function. Then, in the function's code, use a command to get the data from the widget. For example, the "get_text()" command in PyGObject would get the current text from the specified text box.

    glade-signals
    glade-signals
    • "General" offers various options that are particular for that widget type.
    • "Packing" allows developers to control the way the widget is placed on a container. For instance, increasing the "height" of a button that is placed on "grid" will make the button span multiple rows.
    • "Common" offers settings that are the same across all widgets like the spacing, tool-tip, resizing, etc.
    • "Accessibility" controls various accessibility features.

    Widgets

    The "grid" widget is used to create a container made up of columns and rows while the "box" is one column and multiple rows. "viewport" is one row and one column and is used when the contained widget needs to be placed in a scrollable window. "Notebook" is a container providing tabs. Clicking on a tab while in Glade allows the developer to design the contents if the selected tab.

    Radio buttons are toggled and only one radio-button in a group may be active. Check buttons allow users to check/uncheck zero, one, or more boxes in the group.

    A "Label" is text that is a widget that displays the desired text. A "Link button" is a label that offers a hyperlink.

    A "Button" can be pressed to trigger an action and remains in one state. The "Toggle button" exists as either pressed or unpressed. Each state keeps some condition active/true. Changing the button's state may stop the previous action and activate another state.

    glade-sample2
    glade-sample2

    The "Progress Bar" shows the current process based on the fullness of a bar. A "Level Bar" completes the same action, but the bar is filled with blocks on each step. The "Spinner" can be used to show that the program is loading, processing data, or still active (not locked-up or frozen).

    glade-sample
    glade-sample

    Many other widgets are available, but these are the ones many newbies should understand.

    Sample Code

    Below is code for a GTK program that is used to create xdg-desktop files.

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    # vim:fileencoding=utf-8
    """@brief Create Desktop Entry Files
    @file desktop-entry-maker
    @author Devyn Collier Johnson <DevynCJohnson@Gmail.com>
    @copyright LGPLv3
    @version 2016.03.22
    
    @section DESCRIPTION
     - http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
     - http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
    
    @section LICENSE
    GNU Lesser General Public License v3
    Copyright (c) Devyn Collier Johnson, All rights reserved.
    
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 3.0 of the License, or (at your option) any later version.
    
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public
    License along with this library.
    """
    
    
    # pylint: disable=C0103,E1101
    
    
    import stat
    from os import chmod, stat as osstat
    
    from gi.repository import Gtk
    
    
    _GUI = """<?xml version="1.0" encoding="UTF-8"?>
    <!-- Generated with glade 3.18.3
    
    Copyright (C) LGPLv3
    
    This file is part of Desktop-Entry-Maker.
    
    Desktop-Entry-Maker is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    Desktop-Entry-Maker is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public License
    along with Desktop-Entry-Maker.  If not, see <http://www.gnu.org/licenses/&gt;.
    
    Author: Devyn Collier Johnson
    
    -->
    <interface>
      <requires lib="gtk+" version="3.12"/>
      <!-- interface-license-type lgplv3 -->
      <!-- interface-name Desktop-Entry-Maker -->
      <!-- interface-description Create Desktop Entry Files -->
      <!-- interface-copyright LGPLv3 -->
      <!-- interface-authors Devyn Collier Johnson -->
      <object class="GtkApplicationWindow" id="desktop_entry_window">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="title" translatable="yes">Desktop-Entry Maker</property>
        <property name="default_width">600</property>
        <property name="default_height">600</property>
        <property name="icon_name">applications-development</property>
        <property name="show_menubar">False</property>
        <signal name="damage-event" handler="_winexit" swapped="no"/>
        <signal name="delete-event" handler="_winexit" swapped="no"/>
        <signal name="destroy" handler="_winexit" swapped="no"/>
        <signal name="destroy-event" handler="_winexit" swapped="no"/>
        <child>
          <object class="GtkBox" id="box1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="margin_left">5</property>
            <property name="margin_right">5</property>
            <property name="margin_top">5</property>
            <property name="margin_bottom">5</property>
            <property name="orientation">vertical</property>
            <property name="spacing">5</property>
            <child>
              <object class="GtkGrid" id="entry_grid">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="column_spacing">5</property>
                <property name="row_homogeneous">True</property>
                <child>
                  <object class="GtkLabel" id="label_name">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Application's Name (Required)</property>
                    <property name="label" translatable="yes">Name</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_name">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Application's Name (Required)</property>
                    <property name="hexpand">True</property>
                    <property name="primary_icon_tooltip_text" translatable="yes">The program's name (will be seen in menus)</property>
                    <property name="placeholder_text" translatable="yes">*Required*</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_execute">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Command or path to executable (Required)
    Arguments
    %f - Single file
    %F - File list
    %u - Single URL
    %U - URL List</property>
                    <property name="label" translatable="yes">Execute</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">2</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_execute">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Command or path to executable (Required)
    Arguments
    %f - Single file
    %F - File list
    %u - Single URL
    %U - URL List</property>
                    <property name="hexpand">True</property>
                    <property name="placeholder_text" translatable="yes">*Required*</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">2</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_genericname">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Used to indicate the application's general purpose
    Example: LibreOffice = Office Suite</property>
                    <property name="label" translatable="yes">Generic Name</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">1</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_genericname">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Used to indicate the application's general purpose
    Example: LibreOffice = Office Suite</property>
                    <property name="hexpand">True</property>
                    <property name="placeholder_text" translatable="yes">Office Suite</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">1</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_version">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Application's version number (optional)</property>
                    <property name="label" translatable="yes">Version</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">3</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_version">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Application's version number (optional)</property>
                    <property name="hexpand">True</property>
                    <property name="placeholder_text" translatable="yes">1.0</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">3</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_comment">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Tooltip comment (optional)</property>
                    <property name="label" translatable="yes">Comment</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">4</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_comment">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Tooltip comment (optional)</property>
                    <property name="hexpand">True</property>
                    <property name="placeholder_text" translatable="yes">Use a descriptive comment</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">4</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_category">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Application categories (separated with a semicolon)
    Examples:
    Development
    Education
    Game
    GTK
    Java
    Office
    Settings
    System
    Utility</property>
                    <property name="label" translatable="yes">Categories</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">7</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_category">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Application categories (separated with a semicolon)
    Examples:
    Development
    Education
    Game
    GTK
    Java
    Office
    Settings
    System
    Utility</property>
                    <property name="hexpand">True</property>
                    <property name="placeholder_text" translatable="yes">System;Development;</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">7</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_nodisplay">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Do not add application to "open with" and desktop/application menus</property>
                    <property name="label" translatable="yes">NoDisplay</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">9</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkCheckButton" id="check_nodisplay">
                    <property name="label" translatable="yes">True</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip_text" translatable="yes">Do not add application to "open with" and desktop/application menus</property>
                    <property name="halign">center</property>
                    <property name="xalign">0</property>
                    <property name="draw_indicator">True</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">9</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_terminal">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Run in a terminal?</property>
                    <property name="label" translatable="yes">Terminal</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">10</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkCheckButton" id="check_terminal">
                    <property name="label" translatable="yes">True</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip_text" translatable="yes">Run in a terminal?</property>
                    <property name="halign">center</property>
                    <property name="xalign">0</property>
                    <property name="draw_indicator">True</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">10</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_type">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Entry Type such as "Application", "Link", or "Directory" (Required)</property>
                    <property name="label" translatable="yes">Type</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">8</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkComboBoxText" id="combobox_type">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Entry Type such as "Application", "Link", or "Directory" (Required)</property>
                    <property name="hexpand">True</property>
                    <property name="active">0</property>
                    <items>
                      <item translatable="yes">Application</item>
                      <item translatable="yes">Link</item>
                      <item translatable="yes">Directory</item>
                    </items>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">8</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_icon">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Icon path or icon name (optional)
    $HOME/.icons
    $XDG_DATA_DIRS/icons
    /usr/share/pixmaps</property>
                    <property name="label" translatable="yes">Icon</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">6</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_icon">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Icon path or icon name (optional)
    $HOME/.icons
    $XDG_DATA_DIRS/icons
    /usr/share/pixmaps</property>
                    <property name="hexpand">True</property>
                    <property name="placeholder_text" translatable="yes">Name or Path (/usr/share/icons/)</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">6</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label_keywords">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="tooltip_text" translatable="yes">Keywords for searching (optional)
    Separate words with a semicolon</property>
                    <property name="label" translatable="yes">Keywords</property>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">5</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="entry_keyword">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="tooltip_text" translatable="yes">Keywords for searching (optional)
    Separate words with a semicolon</property>
                    <property name="hexpand">True</property>
                    <property name="placeholder_text" translatable="yes">editor;cpu;programming;</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">5</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkSeparator" id="separator1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="padding">5</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkGrid" id="btn_grid">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="column_homogeneous">True</property>
                <child>
                  <object class="GtkButton" id="btn_close">
                    <property name="label">gtk-close</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">Close this application</property>
                    <property name="halign">center</property>
                    <property name="use_stock">True</property>
                    <property name="image_position">right</property>
                    <property name="always_show_image">True</property>
                    <signal name="clicked" handler="_winexit" object="desktop_entry_window" swapped="no"/>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="_save_as">
                    <property name="label">gtk-save-as</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="tooltip_text" translatable="yes">Create the Desktop-Entry file in the selected location</property>
                    <property name="halign">center</property>
                    <property name="use_stock">True</property>
                    <property name="always_show_image">True</property>
                    <signal name="clicked" handler="_save_as" object="desktop_entry_window" swapped="no"/>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">0</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="pack_type">end</property>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="label_about">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">LGPLv3
    Devyn Collier Johnson
    &lt;DevynCJohnson@Gmail.com&gt;
    DCJTech.info
    Version 2016.01.01</property>
                <property name="justify">center</property>
                <property name="selectable">True</property>
                <property name="track_visited_links">False</property>
                <attributes>
                  <attribute name="style" value="oblique"/>
                </attributes>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">3</property>
              </packing>
            </child>
          </object>
        </child>
      </object>
    </interface>"""
    
    _FILECHOOSER = """<?xml version="1.0" encoding="UTF-8"?>
    <!-- Generated with glade 3.18.3
    
    Copyright (C) LGPLv3
    
    This file is part of File Chooser.
    
    File Chooser is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    File Chooser is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public License
    along with File Chooser.  If not, see <http://www.gnu.org/licenses/&gt;.
    
    Author: Devyn Collier Johnson
    
    -->
    <interface>
      <requires lib="gtk+" version="3.12"/>
      <!-- interface-license-type lgplv3 -->
      <!-- interface-name File Chooser -->
      <!-- interface-description Select a file -->
      <!-- interface-copyright LGPLv3 -->
      <!-- interface-authors Devyn Collier Johnson -->
      <object class="GtkApplicationWindow" id="ezwin">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="title" translatable="yes">Choose a File</property>
        <property name="window_position">center-on-parent</property>
        <property name="default_width">700</property>
        <property name="default_height">500</property>
        <property name="destroy_with_parent">True</property>
        <property name="icon_name">system-file-manager</property>
        <property name="type_hint">dialog</property>
        <property name="show_menubar">False</property>
        <signal name="delete-event" handler="_winexit" object="ezwin" swapped="no"/>
        <signal name="destroy-event" handler="_winexit" object="ezwin" swapped="no"/>
        <child>
          <object class="GtkBox" id="box">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <object class="GtkFileChooserWidget" id="filechooser">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="margin_bottom">5</property>
                <property name="create_folders">False</property>
                <property name="preview_widget_active">False</property>
                <property name="use_preview_label">False</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkCheckButton" id="chkbtn2">
                <property name="label" translatable="yes">Select current location</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">False</property>
                <property name="tooltip_text" translatable="yes">Marked - The current location/folder is returned
    
    Empty - The selected folder is returned</property>
                <property name="halign">center</property>
                <property name="valign">center</property>
                <property name="xalign">0</property>
                <property name="draw_indicator">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
              <object class="GtkGrid" id="grid">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="margin_left">5</property>
                <property name="margin_right">5</property>
                <property name="margin_top">5</property>
                <property name="column_homogeneous">True</property>
                <child>
                  <object class="GtkButton" id="btn1">
                    <property name="label">gtk-ok</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip_text" translatable="yes">Submit selection to the program that opened this dialog.</property>
                    <property name="halign">start</property>
                    <property name="valign">center</property>
                    <property name="margin_top">5</property>
                    <property name="margin_bottom">5</property>
                    <property name="use_stock">True</property>
                    <property name="always_show_image">True</property>
                    <signal name="clicked" handler="_select" object="filechooser" swapped="no"/>
                  </object>
                  <packing>
                    <property name="left_attach">0</property>
                    <property name="top_attach">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkCheckButton" id="chkbtn1">
                    <property name="label" translatable="yes">View hidden files</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip_text" translatable="yes">Marked - Show hidden files
    Empty - Hidden files not seen</property>
                    <property name="halign">center</property>
                    <property name="valign">center</property>
                    <property name="xalign">0</property>
                    <property name="draw_indicator">True</property>
                    <signal name="toggled" handler="_hidden" object="filechooser" swapped="no"/>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="top_attach">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="btn2">
                    <property name="label">gtk-cancel</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">False</property>
                    <property name="tooltip_text" translatable="yes">Cancel</property>
                    <property name="halign">end</property>
                    <property name="valign">center</property>
                    <property name="margin_top">5</property>
                    <property name="margin_bottom">5</property>
                    <property name="use_stock">True</property>
                    <property name="image_position">right</property>
                    <property name="always_show_image">True</property>
                    <signal name="clicked" handler="_cancel" object="ezwin" swapped="no"/>
                  </object>
                  <packing>
                    <property name="left_attach">2</property>
                    <property name="top_attach">0</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">4</property>
              </packing>
            </child>
          </object>
        </child>
      </object>
    </interface>"""
    
    
    def write2file(_filename: str, _write) -> None:
        """Send data to new file or overwrite file"""
        with open(_filename, mode='wt', encoding='utf-8') as _file:
            _file.write(str(_write))
        return None
    
    
    def ezfilech() -> list or str:
        """File Chooser Dialog"""
        _init_path = ''
        _viewhidden = False
        _local = True
        filewin = Gtk.Builder()
        filewin.add_from_string(buffer=_FILECHOOSER)
        _filew = filewin.get_object('filechooser')
        _chkbtn_hidden = filewin.get_object('chkbtn1')
        _chkbtn_dir = filewin.get_object('chkbtn2')
        _out = []
        _chkbtn_dir.set_visible(False)
        _filew.set_create_folders(True)
        _filew.set_local_only(_local)
        _filew.set_show_hidden(_viewhidden)
        _chkbtn_hidden.set_active(_viewhidden)
        if _init_path:
            try:
                _filew.set_current_folder(_init_path)
            except (OSError, NameError, TypeError, ValueError):
                pass
        _filew.set_action(Gtk.FileChooserAction.SAVE)
        _filew.set_do_overwrite_confirmation(True)
    
        # Handler Functions
        def _winexit(*_x) -> None:  # pylint: disable=W0613
            """Close application"""
            nonlocal _out
            _out = 'Exit'
            Gtk.main_quit()
            return
    
        def _cancel(*_x) -> None:  # pylint: disable=W0613
            """Cancel and close"""
            nonlocal _out
            _out = 'Cancel'
            Gtk.main_quit()
            return
    
        def _select(*_x) -> None:  # pylint: disable=W0613
            """Select files"""
            nonlocal _out
            _out = ' '.join(_filew.get_filenames())
            Gtk.main_quit()
            return
    
        def _hidden(_widget, *_x) -> None:  # pylint: disable=W0613
            """Show hidden files"""
            _widget.set_show_hidden(not _widget.get_show_hidden())
            return
    
        filewin.connect_signals({
            '_winexit': _winexit,
            '_cancel': _cancel,
            '_select': _select,
            '_hidden': _hidden,
        })
        Gtk.main()
        return _out
    
    
    class MainWin():  # pylint: disable=R0903
        """Main Window"""
        def __init__(self):
            """Main window"""
            self.ui = Gtk.Builder()
            self.ui.add_from_string(buffer=_GUI)
            # Match signal to function (handler)
            self.ui.connect_signals({
                '_winexit': Gtk.main_quit,
                '_save_as': self._save_as,
            })
    
        # Buttons
        def _save_as(self, *_x) -> None:  # noqa C901  # pylint: disable=R0912,R0914,R0915,W0613
            """Save XDG *.desktop file"""
            # Get objects
            entry_name = self.ui.get_object(r'entry_name')
            entry_genericname = self.ui.get_object(r'entry_genericname')
            entry_execute = self.ui.get_object(r'entry_execute')
            entry_icon = self.ui.get_object(r'entry_icon')
            entry_version = self.ui.get_object(r'entry_version')
            combobox_type = self.ui.get_object(r'combobox_type')
            check_terminal = self.ui.get_object(r'check_terminal')
            check_nodisplay = self.ui.get_object(r'check_nodisplay')
            entry_comment = self.ui.get_object(r'entry_comment')
            entry_keyword = self.ui.get_object(r'entry_keyword')
            entry_category = self.ui.get_object(r'entry_category')
            # Get Data
            _entry_name = entry_name.get_text()
            _entry_genericname = entry_genericname.get_text()
            _entry_execute = entry_execute.get_text()
            _entry_icon = entry_icon.get_text()
            _entry_version = entry_version.get_text()
            _combobox_type = str(combobox_type.get_active_text())
            _check_terminal = str(check_terminal.get_active()).casefold()
            _check_nodisplay = str(check_nodisplay.get_active()).casefold()
            _entry_comment = entry_comment.get_text()
            _entry_keyword = entry_keyword.get_text()
            _entry_category = entry_category.get_text()
            if not len(_entry_name) or not len(_entry_execute):
                return
            elif not _entry_name[0].isalnum():
                return
            if not len(_entry_version):
                _entry_version = '1.0'
            if not len(_entry_comment):
                _entry_comment = _entry_name
            if 'none' in _check_terminal.casefold():
                _check_terminal = 'false'
            if 'none' in _check_nodisplay.casefold():
                _check_nodisplay = 'false'
            if 'link' in _combobox_type.casefold():
                _entry_type = str(
                    '\nType=Link' +
                    '\nURL=' + _entry_execute
                )
            elif 'directory' in _combobox_type.casefold():
                _entry_type = '\nType=Directory'
            else:
                _entry_type = str(
                    '\nType=Application' +
                    '\nExec=' + _entry_execute
                )
            # Create Data
            _data = str(
                '#!/usr/bin/env xdg-open\n' +
                '[Desktop Entry]' +
                '\nName=' + _entry_name +
                '\nGenericName=' + _entry_genericname +
                _entry_type +
                '\nNoDisplay=' + _check_nodisplay +
                '\nVersion=' + _entry_version +
                '\nCategories=' + _entry_category +
                '\nTerminal=' + _check_terminal +
                '\nIcon=' + _entry_icon +
                '\nComment=' + _entry_comment +
                '\nKeywords=' + _entry_keyword +
                '\n'
            )
            # Select Location
            _path = ezfilech()
            if _path.lower() == 'cancel' or _path.lower() == 'none':
                return
            if _path == '':
                return
            # Write Data
            try:
                if _path.endswith('.desktop'):
                    write2file(_path, _data)
                else:
                    _path = _path + '.desktop'
                    write2file(_path, _data)
            except Exception:  # pylint: disable=W0703
                return
            # Set Permissions
            _st = osstat(_path)
            chmod(_path, _st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
            # Close/End
            Gtk.main_quit()
            return
    
    
    def main() -> None:
        """Open window and run program"""
        MainWin()
        Gtk.main()
        return
    
    
    if __name__ == '__main__':
        main()

    Further Reading

    Attachments:
    1. glade-about-screen
    2. glade-close-btn
    3. glade-color
    4. glade-color-win
    5. glade-sample
    6. glade-sample2
    7. glade-signals
Viewing 1 post (of 1 total)