Compare commits

...

51 Commits

Author SHA1 Message Date
Matthias Clasen
7bc710ea32 shortcuts: Add a shortcut for search
Make Ctrl-F in the help overlay start search.
2015-10-21 13:17:28 -04:00
Matthias Clasen
6e5b81aebf shortcuts: Add a mnemonic to Show All
Doesn't hurt.
2015-10-21 13:16:54 -04:00
Matthias Clasen
145ffe7dda Don't refilter lazily
Filtering on map was causing noticable jumpiness in the gnome-shell
map animation. Avoid that by eagerly refiltering and reflowing
when the view-name changes.
2015-10-21 13:04:02 -04:00
Matthias Clasen
fd61729f53 shortcuts: Don't require section-name for a single section
Currently, if the section-name is not set, we silently misbehave
and don't ever leave the search results page. We can do better
by just substituting a name.
2015-10-21 13:02:58 -04:00
Matthias Clasen
25629697f2 widget-factory: Beef up help overlay
Add bindings for page 3.
2015-10-21 11:58:59 -04:00
Matthias Clasen
a633a7949d widget-factory: Beef up help overlay
Add a menuitem and shortcut for setting the background on page 2.
2015-10-21 11:14:03 -04:00
Matthias Clasen
42f62a22a7 widget-factory: Beef up the help overlay 2015-10-21 07:48:11 -04:00
Matthias Clasen
d828874e54 widget-factory: Limit page 2 accels to page 2
Some of them cause nasty warnings when triggered from other pages.
2015-10-21 07:47:41 -04:00
Matthias Clasen
58cca05ee2 shortcuts: Add some margin around 'no results'
Otherwise, things may appear cramped.
2015-10-21 06:52:56 -04:00
Matthias Clasen
27ed7508ce Fix a compiler warning 2015-10-21 06:51:25 -04:00
Matthias Clasen
62a57ef4e0 Add documentation for new application window API 2015-10-21 06:39:09 -04:00
Matthias Clasen
df5c1e3b42 Simplify action handling
We don't need a separate flag to track the presence of
the show-help-overlay action, and we can just create the
action directly.
2015-10-21 06:31:27 -04:00
Matthias Clasen
0d1cbcda6e Add an automatic help overlay to gtk3-widget-factory
This is just to verify that the resource loading works.
The help overlay still needs to get populated properly.
2015-10-21 00:14:38 -04:00
Matthias Clasen
2867a7dfa3 Add automatic help overlay support to GtkApplication
When the $(resource_prefix)/gtk/help-overlay.ui resource exists,
load a GtkShortcutsWindow from it for each GtkApplicationWindow,
and set up a win.show-help-overlay action with accels <Primary>F1
and <Primary>? to show it.
2015-10-21 00:11:59 -04:00
Matthias Clasen
d0db025058 shortcuts: Set window type hint
Setting the type hint to dialog gives gnome-shell the push it
needs to present the window nicely.
2015-10-20 23:57:27 -04:00
Matthias Clasen
deeaa94a50 shortcuts: Allow page switching with touch
Allow horizontal pans to switch between pages in the shortcuts window.
2015-10-20 22:59:46 -04:00
Matthias Clasen
08e12b9241 shortcuts: Add key bindings to switch pages
Allow both Page Up/Down and Ctrl-Page Up/Down to switch between
pages in the shortcuts window.
2015-10-20 22:38:34 -04:00
Matthias Clasen
f674b26d80 shortcuts: Add mnemonics for pages
Allow Alt-1, Alt-2 and so forth, to switch pages in the shortcuts
window.
2015-10-20 22:20:18 -04:00
Matthias Clasen
3539a2fd0c shortcuts: Make 'Show All' a normal button
The toggle button was somewhat awkward in that it jumped out
underneath the pointer if you toggled it. Instead, make it a normal
button that disappears when it is clicked.
2015-10-20 22:12:59 -04:00
Matthias Clasen
5c8674b66e Drop remaining internal API
If we do this API-less, lets go all the way.
2015-10-16 16:54:31 -04:00
Matthias Clasen
7343cec577 Finish up help overlay work
This commit makes the various types public and adds documentation.
2015-10-16 16:01:28 -04:00
Matthias Clasen
b787772c14 Restructure the shortcuts demo
Splitting things in individual ui files will make it easier to
reuse this content in the docs.
2015-10-16 11:48:23 -04:00
Matthias Clasen
6137a3c707 fix the build 2015-10-16 10:58:42 -04:00
Matthias Clasen
691f0d617e Balance the clocks shortcuts demo better
We have a max-height property that can be used to influence
the packing of the columns, use it.
2015-10-16 10:47:55 -04:00
Matthias Clasen
51bf0f8f6e shortcuts: Fix a typo
We were removing the wrong widget from the size group here, causing
warnings now that we actually move these widgets between columns and
thereby change their size groups.
2015-10-16 10:46:59 -04:00
Matthias Clasen
6f9a39c883 Reflow shortcuts sections when needed
When the section gets filtered by view, we need to reflow the
groups to avoid partially filled pages and columns that look
odd.
2015-10-16 10:46:10 -04:00
Matthias Clasen
d99f2be837 Major changes
Drop the explicit page and column classes and markup, and create
the necessary structures on the fly. Also drop the custom markup
and just use standard GtkBuilder markup for everything.
2015-10-14 01:15:04 -04:00
Matthias Clasen
337f4e8f95 Fix an oversight in ensuring search item uniqueness
We were using a guaranteed-to-be-NULL string instead of the
one we were actually meaning to use.
2015-10-13 18:47:51 -04:00
Matthias Clasen
03ef1adfb3 Add window title 2015-10-13 18:31:08 -04:00
Matthias Clasen
cb9df7cbe4 Beef up the shortcuts demo more
Add the GEdit window from the mockups.
2015-10-13 09:03:19 -04:00
Matthias Clasen
2e3e788b0b Hide the bottom box in sections until needed
This avoids some extraneous whitespace.
2015-10-13 08:58:15 -04:00
Matthias Clasen
7993feccf5 Beef up the shortcuts example more
Add separate buttons for showing the full and filtered Clocks
example, and make the buttons work more than once.
2015-10-13 08:28:50 -04:00
Matthias Clasen
0226669e14 Simplify shortcuts demo
No need to specify the initial section explicitly anymore.
2015-10-13 08:16:24 -04:00
Matthias Clasen
a281a6f159 Improve the section name handling
Make it so that you don't have to explicitly specify the initial
section in the ui file - the first one will be shown initially in
that case.

Also fix the case where the section-name property is specified
before the sections are added.
2015-10-13 08:14:09 -04:00
Matthias Clasen
821505dd47 Add section filtering by view
This adds the "Show All" button that can be seen in the mockups.
2015-10-13 07:40:08 -04:00
Matthias Clasen
5040c0d650 More updates to the shortcuts demo
Mark all groups in the clocks example with views.
2015-10-13 07:38:09 -04:00
Matthias Clasen
bfd9579dcd Rename some private classes
GtkShortcutsView is now GtkShortcutsSection to better match
the terminology in the design.
2015-10-13 00:37:15 -04:00
Matthias Clasen
3511ef4960 shortcuts: Add an empty search page
Show a nice page when no shortcuts are found.
2015-10-13 00:28:11 -04:00
Matthias Clasen
555de3dcb6 Improve shortcuts window title handling
With a single section, avoid the dropdown and just say
"Shortcuts" in the window title. Also, make "Search Results"
a simple window title.
2015-10-13 00:01:42 -04:00
Matthias Clasen
22bc951195 Use alternative accelerators in the shortcuts demo 2015-10-12 23:41:36 -04:00
Matthias Clasen
b47094c81d Allow alternative accelerators
Allow showing multiple accelerators as alternatives for a single
action, by putting them both in the accelerator property, separated
by a space.
2015-10-12 22:33:51 -04:00
Matthias Clasen
7905ee8bcc Use a better glyph for space
Unicode has ␣, lets use it.
2015-10-12 12:44:52 -04:00
Matthias Clasen
54c4961278 Beef up the shortcuts window demo more
Add more of the complications seen in mockups.
2015-10-12 12:40:56 -04:00
Matthias Clasen
56438b21a6 shortcut label: Improve accelerator formatting
This change decouples the formatting we do here from the one
done for accel labels. With this change, Ctrl+Left is rendered
as expected in the shortcuts window.
2015-10-11 19:19:49 -04:00
Matthias Clasen
508f5b2175 gtk-demo: Beef up the shortcuts demo
Add a second shortcuts window with some more complicated accelerators,
which are currently not handled perfectly, such as Ctrl+Left.
2015-10-11 19:19:49 -04:00
Matthias Clasen
8cccd9eece Add some docs 2015-10-11 19:19:49 -04:00
Matthias Clasen
3eee39b59e Add gtkshortcutswindow.h to gtk.h
This was forgotten in the initial commit.
2015-10-11 18:55:22 -04:00
Matthias Clasen
916235523e builder: Support creating GFile objects
This is useful, e.g. when creating GFileIcon objects.
2015-10-11 18:54:27 -04:00
Matthias Clasen
d1cf4946ae gtk-demo: Add a GtkShortcutsWindow demo
This is directly copied from gnome-builder, so it shows its
shortcuts.
2015-10-11 16:48:08 -04:00
Matthias Clasen
6deeffca3b Add some styling for GtkShortcutsWindow
Add some keycap frame around keysyms, and make the stack switcher
buttons rounds. This is very provisional.
2015-10-11 16:41:30 -04:00
Matthias Clasen
a900b445e7 Add GtkShortcutsWindow
This is a toplevel window that is tailored towards showing
help for shortcuts in an application.

This implementation is shamelessly stolen from gnome-builder,
thanks to Christian Hergert.
2015-10-11 16:39:18 -04:00
41 changed files with 5527 additions and 816 deletions

View File

@@ -56,6 +56,7 @@ demos_base = \
scale.c \
search_entry.c \
search_entry2.c \
shortcuts.c \
sidebar.c \
sizegroup.c \
spinbutton.c \

View File

@@ -91,6 +91,12 @@
<gresource prefix="/stack">
<file>stack.ui</file>
</gresource>
<gresource prefix="/shortcuts">
<file>shortcuts.ui</file>
<file>shortcuts-builder.ui</file>
<file>shortcuts-gedit.ui</file>
<file>shortcuts-clocks.ui</file>
</gresource>
<gresource prefix="/revealer">
<file>revealer.ui</file>
</gresource>
@@ -163,6 +169,7 @@
<file>scale.c</file>
<file>search_entry.c</file>
<file>search_entry2.c</file>
<file>shortcuts.c</file>
<file>sizegroup.c</file>
<file>sidebar.c</file>
<file>stack.c</file>
@@ -213,4 +220,8 @@
<gresource prefix="/modelbutton">
<file>modelbutton.ui</file>
</gresource>
<gresource prefix="/icons">
<file>gesture-two-finger-swipe-right.svg</file>
<file>gesture-two-finger-swipe-left.svg</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="80"
height="54"
viewBox="0 0 80.000001 54"
id="svg6660"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="two-finger-swipe-left.svg"
inkscape:export-filename="/home/aday/Scratch/two-finger-swipe-left.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs6662" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-26.486277"
inkscape:cy="27.97415"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:showpageshadow="false"
units="px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata6665">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(1077.1429,-651.07582)">
<g
style="display:inline"
transform="translate(-753.14285,209.07579)"
id="g6613">
<g
id="g6615">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6617"
width="7.99999"
height="24.999994"
x="-288"
y="471"
ry="4.1854858"
rx="3.999995" />
<rect
rx="3.999995"
ry="4.1854858"
y="452.00003"
x="-279"
height="43.999989"
width="7.99999"
id="rect6619"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6621"
width="7.99999"
height="49.000015"
x="-270"
y="447"
ry="4.1854858"
rx="3.999995" />
<rect
rx="3.999995"
ry="4.1854858"
y="460"
x="-261"
height="36.000011"
width="7.99999"
id="rect6623"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6625"
width="7.99999"
height="30.000006"
x="-252"
y="466"
ry="4.1854858"
rx="3.999995" />
<rect
y="483"
x="-288"
height="12.99999"
width="28.999994"
id="rect6627"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
rx="3.999995"
ry="4.1854858"
y="475"
x="-279"
height="21"
width="34.999985"
id="rect6629"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
id="path6631"
sodipodi:type="arc"
sodipodi:cx="-266"
sodipodi:cy="451"
sodipodi:rx="7.4999938"
sodipodi:ry="7.5000024"
sodipodi:start="3.4953343"
sodipodi:end="1.8407347"
d="m -273.03562,448.40192 a 7.4999938,7.5000024 0 0 1 9.43617,-4.50737 7.4999938,7.5000024 0 0 1 4.76917,9.30661 7.4999938,7.5000024 0 0 1 -9.16976,5.02725"
sodipodi:open="true" />
<path
d="m -268.10552,458.34925 a 7.4999938,7.5000024 0 0 1 -9.38146,4.80209 7.4999938,7.5000024 0 0 1 -4.92078,-9.31976 7.4999938,7.5000024 0 0 1 9.25653,-5.03869"
sodipodi:end="4.9929531"
sodipodi:start="0.31864739"
sodipodi:ry="7.5000024"
sodipodi:rx="7.4999938"
sodipodi:cy="455.99963"
sodipodi:cx="-275.22797"
sodipodi:type="arc"
id="path6633"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
sodipodi:open="true" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;enable-background:accumulate"
d="m -314,465 -10,-9.5 10,-9.5 z"
id="path6635"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<rect
transform="scale(-1,-1)"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6637"
width="31.999987"
height="4.99999"
x="283"
y="-458" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="80.000008"
height="55.000023"
viewBox="0 0 80.000008 55.000024"
id="svg6535"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="two-finger-swipe-right.svg">
<defs
id="defs6537" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="-59.169932"
inkscape:cy="48.63391"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:showpageshadow="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata6540">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(180,-479.14791)">
<g
style="display:inline"
transform="translate(144,118.14791)"
id="g6509">
<g
id="g6511">
<rect
rx="3.999995"
ry="4.1854858"
y="391"
x="-324"
height="24.999994"
width="7.99999"
id="rect6513"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6515"
width="7.99999"
height="43.999989"
x="-315"
y="372.00003"
ry="4.1854858"
rx="3.999995" />
<rect
rx="3.999995"
ry="4.1854858"
y="367"
x="-306"
height="49.000015"
width="7.99999"
id="rect6517"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6519"
width="7.99999"
height="36.000011"
x="-297"
y="380"
ry="4.1854858"
rx="3.999995" />
<rect
rx="3.999995"
ry="4.1854858"
y="386"
x="-288"
height="30.000006"
width="7.99999"
id="rect6521"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6523"
width="28.999994"
height="12.99999"
x="-324"
y="403" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect6525"
width="34.999985"
height="21"
x="-315"
y="395"
ry="4.1854858"
rx="3.999995" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path6527"
d="m -254,361 10,9.5 -10,9.5 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;enable-background:accumulate" />
<path
sodipodi:open="true"
d="m -309.03562,368.40192 a 7.4999938,7.5000024 0 0 1 9.43617,-4.50737 7.4999938,7.5000024 0 0 1 4.76917,9.30661 7.4999938,7.5000024 0 0 1 -9.16976,5.02725"
sodipodi:end="1.8407347"
sodipodi:start="3.4953343"
sodipodi:ry="7.5000024"
sodipodi:rx="7.4999938"
sodipodi:cy="371"
sodipodi:cx="-302"
sodipodi:type="arc"
id="path6529"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:open="true"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
id="path6531"
sodipodi:type="arc"
sodipodi:cx="-311.22797"
sodipodi:cy="375.99963"
sodipodi:rx="7.4999938"
sodipodi:ry="7.5000024"
sodipodi:start="0.31864739"
sodipodi:end="4.9929531"
d="m -304.10552,378.34925 a 7.4999938,7.5000024 0 0 1 -9.38146,4.80209 7.4999938,7.5000024 0 0 1 -4.92078,-9.31976 7.4999938,7.5000024 0 0 1 9.25653,-5.03869" />
<rect
y="368"
x="-295"
height="4.99999"
width="41.999992"
id="rect6533"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4a90d9;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -0,0 +1,454 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.17 -->
<object class="GFileIcon" id="left-swipe-icon">
<property name="file">resource:///icons/gesture-two-finger-swipe-left.svg</property>
</object>
<object class="GFileIcon" id="right-swipe-icon">
<property name="file">resource:///icons/gesture-two-finger-swipe-right.svg</property>
</object>
<object class="GtkShortcutsWindow" id="shortcuts-builder">
<property name="modal">1</property>
<child>
<object class="GtkShortcutsSection">
<property name="visible">1</property>
<property name="section-name">editor</property>
<property name="title" translatable="yes">Editor Shortcuts</property>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Global Search</property>
<property name="accelerator">&lt;ctrl&gt;period</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Preferences</property>
<property name="accelerator">&lt;ctrl&gt;comma</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Command Bar</property>
<property name="accelerator">&lt;ctrl&gt;Return</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Terminal</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;t</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Keyboard Shortcuts</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;question</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Panels</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Toggle left panel</property>
<property name="accelerator">F9</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Toggle right panel</property>
<property name="accelerator">&lt;shift&gt;F9</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Toggle bottom panel</property>
<property name="accelerator">&lt;ctrl&gt;F9</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Touchpad gestures</property>
<child>
<object class="GtkShortcutsGesture">
<property name="visible">1</property>
<property name="title" translatable="yes">Switch to the next document</property>
<property name="subtitle" translatable="yes">Two finger swipe right</property>
<property name="icon">right-swipe-icon</property>
</object>
</child>
<child>
<object class="GtkShortcutsGesture">
<property name="visible">1</property>
<property name="title" translatable="yes">Switch to the previous document</property>
<property name="subtitle" translatable="yes">Two finger swipe left</property>
<property name="icon">left-swipe-icon</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Files</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;n</property>
<property name="title" translatable="yes">Create new document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;o</property>
<property name="title" translatable="yes">Open a document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;s</property>
<property name="title" translatable="yes">Save the document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;w</property>
<property name="title" translatable="yes">Close the document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;alt&gt;Page_Down</property>
<property name="title" translatable="yes">Switch to the next document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;alt&gt;Page_Up</property>
<property name="title" translatable="yes">Switch to the previous document</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Find and replace</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;f</property>
<property name="title" translatable="yes">Find</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;g</property>
<property name="title" translatable="yes">Find the next match</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;g</property>
<property name="title" translatable="yes">Find the previous match</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;k</property>
<property name="title" translatable="yes">Clear highlight</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Copy and Paste</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;c</property>
<property name="title" translatable="yes">Copy selected text to clipboard</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;x</property>
<property name="title" translatable="yes">Cut selected text to clipboard</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;v</property>
<property name="title" translatable="yes">Paste text from clipboard</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Undo and Redo</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;z</property>
<property name="title" translatable="yes">Undo previous command</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;z</property>
<property name="title" translatable="yes">Redo previous command</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Editing</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;a</property>
<property name="title" translatable="yes">Increment number at cursor</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;x</property>
<property name="title" translatable="yes">Decrement number at cursor</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;j</property>
<property name="title" translatable="yes">Join selected lines</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;space</property>
<property name="title" translatable="yes">Show completion window</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Insert</property>
<property name="title" translatable="yes">Toggle overwrite</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;alt&gt;i</property>
<property name="title" translatable="yes">Reindent line</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Navigation</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;n</property>
<property name="title" translatable="yes">Move to next error in file</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;p</property>
<property name="title" translatable="yes">Move to previous error in file</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;shift&gt;&lt;alt&gt;Left</property>
<property name="title" translatable="yes">Move to previous edit location</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;shift&gt;&lt;alt&gt;Right</property>
<property name="title" translatable="yes">Move to next edit location</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;period</property>
<property name="title" translatable="yes">Jump to definition of symbol</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;&lt;shift&gt;Up</property>
<property name="title" translatable="yes">Move sectionport up within the file</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;&lt;shift&gt;Down</property>
<property name="title" translatable="yes">Move sectionport down within the file</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;&lt;shift&gt;End</property>
<property name="title" translatable="yes">Move sectionport to end of file</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;&lt;shift&gt;Home</property>
<property name="title" translatable="yes">Move sectionport to beginning of file</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;percent</property>
<property name="title" translatable="yes">Move to matching bracket</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Selections</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;a</property>
<property name="title" translatable="yes">Select all</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;backslash</property>
<property name="title" translatable="yes">Unselect all</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsSection">
<property name="visible">1</property>
<property name="section-name">terminal</property>
<property name="title" translatable="yes">Terminal Shortcuts</property>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Global Search</property>
<property name="accelerator">&lt;ctrl&gt;period</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Preferences</property>
<property name="accelerator">&lt;ctrl&gt;comma</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Command Bar</property>
<property name="accelerator">&lt;ctrl&gt;Return</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Terminal</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;t</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes">Keyboard Shortcuts</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;question</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Copy and Paste</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;c</property>
<property name="title" translatable="yes">Copy selected text to clipboard</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;v</property>
<property name="title" translatable="yes">Paste text from clipboard</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.17 -->
<object class="GtkShortcutsWindow" id="shortcuts-clocks">
<property name="modal">1</property>
<child>
<object class="GtkShortcutsSection">
<property name="visible">1</property>
<property name="section-name">shortcuts</property>
<property name="max-height">10</property>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;Page_Down</property>
<property name="title" translatable="yes">Go to the next section</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;Page_Up</property>
<property name="title" translatable="yes">Go to the previous section</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;Q</property>
<property name="title" translatable="yes">Quit</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;Left</property>
<property name="title" translatable="yes">Forward</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;Right</property>
<property name="title" translatable="yes">Back</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="view">world</property>
<property name="title" translatable="yes">World Clocks</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;N</property>
<property name="title" translatable="yes">Add a world clock</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;S</property>
<property name="title" translatable="yes">Select world clocks</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="view">alarm</property>
<property name="title" translatable="yes">Alarm</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;N</property>
<property name="title" translatable="yes">Add an alarm</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;S</property>
<property name="title" translatable="yes">Select alarms</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="view">stopwatch</property>
<property name="title" translatable="yes">Stopwatch</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Return space</property>
<property name="title" translatable="yes">Start / Stop / Continue</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">L</property>
<property name="title" translatable="yes">Lap</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Delete</property>
<property name="title" translatable="yes">Reset</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="view">timer</property>
<property name="title" translatable="yes">Timer</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Return space</property>
<property name="title" translatable="yes">Start / Stop / Pause</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Delete</property>
<property name="title" translatable="yes">Reset</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.17 -->
<object class="GFileIcon" id="left-swipe-icon">
<property name="file">resource:///icons/gesture-two-finger-swipe-left.svg</property>
</object>
<object class="GFileIcon" id="right-swipe-icon">
<property name="file">resource:///icons/gesture-two-finger-swipe-right.svg</property>
</object>
<object class="GtkShortcutsWindow" id="shortcuts-gedit">
<property name="modal">1</property>
<child>
<object class="GtkShortcutsSection">
<property name="visible">1</property>
<property name="section-name">shortcuts</property>
<property name="max-height">12</property>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Touchpad gestures</property>
<child>
<object class="GtkShortcutsGesture">
<property name="visible">1</property>
<property name="title" translatable="yes">Switch to the next document</property>
<property name="subtitle" translatable="yes">Two finger swipe right</property>
<property name="icon">right-swipe-icon</property>
</object>
</child>
<child>
<object class="GtkShortcutsGesture">
<property name="visible">1</property>
<property name="title" translatable="yes">Switch to the previous document</property>
<property name="subtitle" translatable="yes">Two finger swipe left</property>
<property name="icon">left-swipe-icon</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Documents</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;N</property>
<property name="title" translatable="yes">Create new document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;O</property>
<property name="title" translatable="yes">Open a document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;S</property>
<property name="title" translatable="yes">Save the document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;W</property>
<property name="title" translatable="yes">Close the document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;Alt&gt;Page_Down</property>
<property name="title" translatable="yes">Switch to the next document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;Alt&gt;Page_Up</property>
<property name="title" translatable="yes">Switch to the previous document</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Find and Replace</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;F</property>
<property name="title" translatable="yes">Find</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;G</property>
<property name="title" translatable="yes">Find the next match</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;Shift&gt;G</property>
<property name="title" translatable="yes">Find the previous match</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;H</property>
<property name="title" translatable="yes">Find and Replace</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;Shift&gt;K</property>
<property name="title" translatable="yes">Clear highlight</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;I</property>
<property name="title" translatable="yes">Go to line</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Tools</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;shift&gt;F7</property>
<property name="title" translatable="yes">Check spelling</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Miscellaneous</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">F11</property>
<property name="title" translatable="yes">Fullscreen on / off</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;P</property>
<property name="title" translatable="yes">Print the document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Insert</property>
<property name="title" translatable="yes">Toggle insert / overwrite</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,92 @@
/* Shortcuts Window
*
* GtkShortcutsWindow is a window that provides a help overlay
* for shortcuts and gestures in an application.
*/
#include <gtk/gtk.h>
static void
show_shortcuts (GtkWidget *window,
const gchar *id,
const gchar *view)
{
GtkBuilder *builder;
GtkWidget *overlay;
gchar *path;
path = g_strdup_printf ("/shortcuts/%s.ui", id);
builder = gtk_builder_new_from_resource (path);
g_free (path);
overlay = GTK_WIDGET (gtk_builder_get_object (builder, id));
gtk_window_set_transient_for (GTK_WINDOW (overlay), GTK_WINDOW (window));
g_object_set (overlay, "view-name", view, NULL);
gtk_widget_show (overlay);
}
static void
builder_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-builder", NULL);
}
static void
gedit_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-gedit", NULL);
}
static void
clocks_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-clocks", NULL);
}
static void
clocks_shortcuts_stopwatch (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-clocks", "stopwatch");
}
GtkWidget *
do_shortcuts (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
static gboolean icons_added = FALSE;
if (!icons_added)
{
icons_added = TRUE;
gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/icons");
}
g_type_ensure (G_TYPE_FILE_ICON);
if (!window)
{
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/shortcuts/shortcuts.ui");
gtk_builder_add_callback_symbols (builder,
"builder_shortcuts", G_CALLBACK (builder_shortcuts),
"gedit_shortcuts", G_CALLBACK (gedit_shortcuts),
"clocks_shortcuts", G_CALLBACK (clocks_shortcuts),
"clocks_shortcuts_stopwatch", G_CALLBACK (clocks_shortcuts_stopwatch),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_screen (GTK_WINDOW (window),
gtk_widget_get_screen (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show_all (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.17 -->
<object class="GtkWindow" id="window1">
<property name="title" translatable="yes">Shortcuts</property>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="margin">50</property>
<property name="spacing">10</property>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="label">Builder</property>
<signal name="clicked" handler="builder_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="label">GEdit</property>
<signal name="clicked" handler="gedit_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="label">Clocks - All</property>
<signal name="clicked" handler="clocks_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="label">Clocks - Stopwatch</property>
<signal name="clicked" handler="clocks_shortcuts_stopwatch" swapped="1" object="window1"/>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -64,6 +64,7 @@ EXTRA_DIST += \
widget-factory.ui \
widget-factory.css \
menus.ui \
help-overlay.ui \
widget-factory.gresource.xml \
data/source.svg \
data/symbolic-source.svg

View File

@@ -0,0 +1,92 @@
<interface>
<object class="GtkShortcutsWindow" id="help_overlay">
<child>
<object class="GtkShortcutsSection">
<property name="visible">1</property>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">F1</property>
<property name="title">Show About Dialog</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Primary&gt;q</property>
<property name="title">Quit</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Primary&gt;d</property>
<property name="title">Switch to dark theme</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title">Traditional</property>
<property name="view">page2</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Primary&gt;s</property>
<property name="title">Search</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Delete</property>
<property name="title">Delete</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Primary&gt;b</property>
<property name="title">Set background</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title">Modern</property>
<property name="view">page3</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Primary&gt;o</property>
<property name="title">Open a file</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Primary&gt;r</property>
<property name="title">Start recording</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Primary&gt;l</property>
<property name="title">Lock or unlock</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -69,6 +69,13 @@ get_busy (GSimpleAction *action,
gtk_widget_set_sensitive (window, FALSE);
}
static gint current_page = 0;
static gboolean
on_page (gint i)
{
return current_page == i;
}
static void
activate_search (GSimpleAction *action,
GVariant *parameter,
@@ -77,6 +84,9 @@ activate_search (GSimpleAction *action,
GtkWidget *window = user_data;
GtkWidget *searchbar;
if (!on_page (2))
return;
searchbar = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "searchbar"));
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (searchbar), TRUE);
}
@@ -89,10 +99,79 @@ activate_delete (GSimpleAction *action,
GtkWidget *window = user_data;
GtkWidget *infobar;
if (!on_page (2))
return;
infobar = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "infobar"));
gtk_widget_show (infobar);
}
static void populate_flowbox (GtkWidget *flowbox);
static void
activate_background (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *window = user_data;
GtkWidget *dialog;
GtkWidget *flowbox;
if (!on_page (2))
return;
dialog = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "selection_dialog"));
flowbox = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "selection_flowbox"));
gtk_widget_show (dialog);
populate_flowbox (flowbox);
}
static void
activate_open (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *window = user_data;
GtkWidget *button;
if (!on_page (3))
return;
button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "open_menubutton"));
gtk_button_clicked (GTK_BUTTON (button));
}
static void
activate_record (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *window = user_data;
GtkWidget *button;
if (!on_page (3))
return;
button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "record_button"));
gtk_button_clicked (GTK_BUTTON (button));
}
static void
activate_lock (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *window = user_data;
GtkWidget *button;
if (!on_page (3))
return;
button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "lockbutton"));
gtk_button_clicked (GTK_BUTTON (button));
}
static void
activate_about (GSimpleAction *action,
GVariant *parameter,
@@ -469,14 +548,26 @@ static void
page_changed_cb (GtkWidget *stack, GParamSpec *pspec, gpointer data)
{
const gchar *name;
GtkWidget *window;
GtkWidget *page;
if (gtk_widget_in_destruction (stack))
return;
name = gtk_stack_get_visible_child_name (GTK_STACK (stack));
window = gtk_widget_get_ancestor (stack, GTK_TYPE_APPLICATION_WINDOW);
g_object_set (gtk_application_window_get_help_overlay (GTK_APPLICATION_WINDOW (window)),
"view-name", name,
NULL);
if (g_str_equal (name, "page1"))
current_page = 1;
else if (g_str_equal (name, "page2"))
current_page = 2;
if (g_str_equal (name, "page3"))
{
current_page = 3;
page = gtk_stack_get_visible_child (GTK_STACK (stack));
set_needs_attention (GTK_WIDGET (page), FALSE);
}
@@ -818,7 +909,7 @@ background_loaded_cb (GObject *source,
}
static void
populate_flowbox (GtkWidget *button, GtkWidget *flowbox)
populate_flowbox (GtkWidget *flowbox)
{
const gchar *location;
GDir *dir;
@@ -831,7 +922,10 @@ populate_flowbox (GtkWidget *button, GtkWidget *flowbox)
GdkPixbuf *pixbuf;
GtkWidget *child;
g_signal_handlers_disconnect_by_func (button, populate_flowbox, flowbox);
if (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (flowbox), "populated")))
return;
g_object_set_data (G_OBJECT (flowbox), "populated", GUINT_TO_POINTER (1));
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 110, 70);
gdk_pixbuf_fill (pixbuf, 0xffffffff);
@@ -1379,7 +1473,11 @@ activate (GApplication *app)
{ "dark", NULL, NULL, "false", change_theme_state },
{ "search", activate_search, NULL, NULL, NULL },
{ "delete", activate_delete, NULL, NULL, NULL },
{ "busy", get_busy, NULL, NULL, NULL }
{ "busy", get_busy, NULL, NULL, NULL },
{ "background", activate_background, NULL, NULL, NULL },
{ "open", activate_open, NULL, NULL, NULL },
{ "record", activate_record, NULL, NULL, NULL },
{ "lock", activate_lock, NULL, NULL, NULL },
};
struct {
const gchar *action_and_target;
@@ -1389,10 +1487,15 @@ activate (GApplication *app)
{ "app.quit", { "<Primary>q", NULL } },
{ "win.dark", { "<Primary>d", NULL } },
{ "win.search", { "<Primary>s", NULL } },
{ "win.delete", { "Delete", NULL } }
{ "win.delete", { "Delete", NULL } },
{ "win.background", { "<Primary>b", NULL } },
{ "win.open", { "<Primary>o", NULL } },
{ "win.record", { "<Primary>r", NULL } },
{ "win.lock", { "<Primary>l", NULL } },
};
gint i;
GPermission *permission;
GAction *action;
g_type_ensure (my_text_view_get_type ());
@@ -1498,6 +1601,7 @@ activate (GApplication *app)
stack = (GtkWidget *)gtk_builder_get_object (builder, "toplevel_stack");
g_signal_connect (widget, "clicked", G_CALLBACK (action_dialog_button_clicked), stack);
g_signal_connect (stack, "notify::visible-child-name", G_CALLBACK (page_changed_cb), NULL);
page_changed_cb (stack, NULL, NULL);
dialog = (GtkWidget *)gtk_builder_get_object (builder, "preference_dialog");
g_signal_connect (dialog, "response", G_CALLBACK (close_dialog), NULL);
@@ -1507,13 +1611,15 @@ activate (GApplication *app)
g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
dialog = (GtkWidget *)gtk_builder_get_object (builder, "selection_dialog");
g_object_set_data (G_OBJECT (window), "selection_dialog", dialog);
widget = (GtkWidget *)gtk_builder_get_object (builder, "text3");
g_signal_connect (dialog, "response", G_CALLBACK (close_selection_dialog), widget);
widget = (GtkWidget *)gtk_builder_get_object (builder, "selection_dialog_button");
g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
widget2 = (GtkWidget *)gtk_builder_get_object (builder, "selection_flowbox");
g_signal_connect (widget, "clicked", G_CALLBACK (populate_flowbox), widget2);
g_object_set_data (G_OBJECT (window), "selection_flowbox", widget2);
g_signal_connect_swapped (widget, "clicked", G_CALLBACK (populate_flowbox), widget2);
widget = (GtkWidget *)gtk_builder_get_object (builder, "charletree");
populate_model ((GtkTreeStore *)gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
@@ -1538,6 +1644,7 @@ activate (GApplication *app)
set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "searchmenuitem")));
set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "darkmenuitem")));
set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "aboutmenuitem")));
set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "bgmenuitem")));
widget2 = (GtkWidget *)gtk_builder_get_object (builder, "tooltextview");
@@ -1580,13 +1687,26 @@ activate (GApplication *app)
gtk_popover_set_default_widget (GTK_POPOVER (widget), widget3);
g_signal_connect (widget2, "notify::text", G_CALLBACK (open_popover_text_changed), widget3);
g_signal_connect_swapped (widget3, "clicked", G_CALLBACK (gtk_widget_hide), widget);
widget = (GtkWidget *)gtk_builder_get_object (builder, "open_menubutton");
g_object_set_data (G_OBJECT (window), "open_menubutton", widget);
widget = (GtkWidget *)gtk_builder_get_object (builder, "record_button");
g_object_set_data (G_OBJECT (window), "record_button", widget);
widget = (GtkWidget *)gtk_builder_get_object (builder, "lockbox");
widget2 = (GtkWidget *)gtk_builder_get_object (builder, "lockbutton");
g_object_set_data (G_OBJECT (window), "lockbutton", widget2);
permission = g_object_new (g_test_permission_get_type (), NULL);
g_object_bind_property (permission, "allowed",
widget, "sensitive",
G_BINDING_SYNC_CREATE);
action = g_action_map_lookup_action (G_ACTION_MAP (window), "open");
g_object_bind_property (permission, "allowed",
action, "enabled",
G_BINDING_SYNC_CREATE);
action = g_action_map_lookup_action (G_ACTION_MAP (window), "record");
g_object_bind_property (permission, "allowed",
action, "enabled",
G_BINDING_SYNC_CREATE);
gtk_lock_button_set_permission (GTK_LOCK_BUTTON (widget2), permission);
g_object_unref (permission);

View File

@@ -9,4 +9,7 @@
<gresource prefix="/org/gtk/WidgetFactory/gtk">
<file preprocess="xml-stripblanks">menus.ui</file>
</gresource>
<gresource prefix="/org/gtk/WidgetFactory/gtk">
<file preprocess="xml-stripblanks">help-overlay.ui</file>
</gresource>
</gresources>

View File

@@ -2485,6 +2485,15 @@ microphone-sensitivity-medium-symbolic</property>
<property name="action_name">win.statusbar</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="bgmenuitem">
<property name="label">_Select Background</property>
<property name="visible">1</property>
<property name="use_action_appearance">0</property>
<property name="use_underline">1</property>
<property name="action_name">win.background</property>
</object>
</child>
</object>
</child>
</object>
@@ -2902,7 +2911,7 @@ microphone-sensitivity-medium-symbolic</property>
<property name="halign">start</property>
<property name="spacing">6</property>
<child>
<object class="GtkMenuButton">
<object class="GtkMenuButton" id="open_menubutton">
<property name="visible">1</property>
<property name="halign">center</property>
<property name="popover">open_popover</property>

View File

@@ -470,7 +470,10 @@ HTML_IMAGES = \
$(srcdir)/images/getting-started-app10.png \
$(srcdir)/images/exampleapp.png \
$(srcdir)/images/flow-box.png \
$(srcdir)/images/inspector.png
$(srcdir)/images/inspector.png \
$(srcdir)/images/gedit-shortcuts.png \
$(srcdir)/images/clocks-shortcuts.png \
$(srcdir)/images/builder-shortcuts.png
if ENABLE_DOC_CROSS_REFERENCES
# Extra options to supply to gtkdoc-fixref

View File

@@ -239,6 +239,15 @@
<xi:include href="xml/gtkpagesetupunixdialog.xml" />
</chapter>
<chapter id="ShortcutsOverview">
<title>Shortcuts Overview</title>
<xi:include href="xml/gtkshortcutswindow.xml" />
<xi:include href="xml/gtkshortcutssection.xml" />
<xi:include href="xml/gtkshortcutsgroup.xml" />
<xi:include href="xml/gtkshortcutsshortcut.xml" />
<xi:include href="xml/gtkshortcutsgesture.xml" />
</chapter>
<chapter id="MiscObjects">
<title>Miscellaneous</title>
<xi:include href="xml/gtkadjustment.xml" />

View File

@@ -7545,6 +7545,8 @@ gtk_application_window_new
gtk_application_window_set_show_menubar
gtk_application_window_get_show_menubar
gtk_application_window_get_id
gtk_application_window_set_help_overlay
gtk_application_window_get_help_overlay
<SUBSECTION Standard>
GTK_TYPE_APPLICATION_WINDOW
@@ -8422,3 +8424,74 @@ GTK_IS_GL_AREA_CLASS
<SUBSECTION Private>
gtk_gl_area_get_type
</SECTION>
<SECTION>
<FILE>gtkshortcutswindow</FILE>
GtkShortcutsWindow
<SUBSECTION Standard>
GTK_TYPE_SHORTCUTS_WINDOW
GTK_SHORTCUTS_WINDOW
GTK_IS_SHORTCUTS_WINDOW
GTK_SHORTCUTS_WINDOW_CLASS
GTK_IS_SHORTCUTS_WINDOW_CLASS
GTK_GET_SHORTCUTS_WINDOW_CLASS
<SUBSECTION Private>
gtk_shortcuts_window_get_type
</SECTION>
<SECTION>
<FILE>gtkshortcutssection</FILE>
GtkShortcutsSection
<SUBSECTION Standard>
GTK_TYPE_SHORTCUTS_SECTION
GTK_SHORTCUTS_SECTION
GTK_IS_SHORTCUTS_SECTION
GTK_SHORTCUTS_SECTION_CLASS
GTK_IS_SHORTCUTS_SECTION_CLASS
GTK_GET_SHORTCUTS_SECTION_CLASS
<SUBSECTION Private>
gtk_shortcuts_section_get_type
</SECTION>
<SECTION>
<FILE>gtkshortcutsgroup</FILE>
GtkShortcutsGroup
<SUBSECTION Standard>
GTK_TYPE_SHORTCUTS_GROUP
GTK_SHORTCUTS_GROUP
GTK_IS_SHORTCUTS_GROUP
GTK_SHORTCUTS_GROUP_CLASS
GTK_IS_SHORTCUTS_GROUP_CLASS
GTK_GET_SHORTCUTS_GROUP_CLASS
<SUBSECTION Private>
gtk_shortcuts_group_get_type
</SECTION>
<SECTION>
<FILE>gtkshortcutsshortcut</FILE>
GtkShortcutsShortcut
<SUBSECTION Standard>
GTK_TYPE_SHORTCUTS_SHORTCUT
GTK_SHORTCUTS_SHORTCUT
GTK_IS_SHORTCUTS_SHORTCUT
GTK_SHORTCUTS_SHORTCUT_CLASS
GTK_IS_SHORTCUTS_SHORTCUT_CLASS
GTK_GET_SHORTCUTS_SHORTCUT_CLASS
<SUBSECTION Private>
<SUBSECTION Private>
gtk_shortcuts_shortcut_get_type
</SECTION>
<SECTION>
<FILE>gtkshortcutsgesture</FILE>
GtkShortcutsGesture
<SUBSECTION Standard>
GTK_TYPE_SHORTCUTS_GESTURE
GTK_SHORTCUTS_GESTURE
GTK_IS_SHORTCUTS_GESTURE
GTK_SHORTCUTS_GESTURE_CLASS
GTK_IS_SHORTCUTS_GESTURE_CLASS
GTK_GET_SHORTCUTS_GESTURE_CLASS
<SUBSECTION Private>
gtk_shortcuts_gesture_get_type
</SECTION>

View File

@@ -173,12 +173,17 @@ gtk_separator_get_type
gtk_separator_menu_item_get_type
gtk_separator_tool_item_get_type
gtk_settings_get_type
gtk_stack_sidebar_get_type
gtk_shortcuts_window_get_type
gtk_shortcuts_section_get_type
gtk_shortcuts_group_get_type
gtk_shortcuts_shortcut_get_type
gtk_shortcuts_gesture_get_type
gtk_size_group_get_type
@ENABLE_ON_X11@gtk_socket_get_type
gtk_spin_button_get_type
gtk_spinner_get_type
gtk_stack_get_type
gtk_stack_sidebar_get_type
gtk_stack_switcher_get_type
gtk_statusbar_get_type
gtk_status_icon_get_type

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -269,6 +269,11 @@ gtk_public_h_sources = \
gtkseparatormenuitem.h \
gtkseparatortoolitem.h \
gtksettings.h \
gtkshortcutsgesture.h \
gtkshortcutsgroup.h \
gtkshortcutssection.h \
gtkshortcutsshortcut.h \
gtkshortcutswindow.h \
gtkshow.h \
gtkstacksidebar.h \
gtksizegroup.h \
@@ -505,6 +510,9 @@ gtk_private_h_sources = \
gtkselectionprivate.h \
gtksidebarrowprivate.h \
gtksettingsprivate.h \
gtkshortcutsgestureprivate.h \
gtkshortcutlabelprivate.h \
gtkshortcutsshortcutprivate.h \
gtksizegroup-private.h \
gtksizerequestcacheprivate.h \
gtksocketprivate.h \
@@ -805,6 +813,12 @@ gtk_base_c_sources = \
gtkseparatormenuitem.c \
gtkseparatortoolitem.c \
gtksettings.c \
gtkshortcutsgesture.c \
gtkshortcutsgroup.c \
gtkshortcutlabel.c \
gtkshortcutsshortcut.c \
gtkshortcutssection.c \
gtkshortcutswindow.c \
gtksidebarrow.c \
gtksizegroup.c \
gtksizerequest.c \

View File

@@ -183,6 +183,11 @@
#include <gtk/gtkseparatormenuitem.h>
#include <gtk/gtkseparatortoolitem.h>
#include <gtk/gtksettings.h>
#include <gtk/gtkshortcutsgesture.h>
#include <gtk/gtkshortcutsgroup.h>
#include <gtk/gtkshortcutssection.h>
#include <gtk/gtkshortcutsshortcut.h>
#include <gtk/gtkshortcutswindow.h>
#include <gtk/gtkshow.h>
#include <gtk/gtkstacksidebar.h>
#include <gtk/gtksizegroup.h>

View File

@@ -38,6 +38,7 @@
#include "gtkaccelmapprivate.h"
#include "gtkicontheme.h"
#include "gtkbuilder.h"
#include "gtkshortcutswindow.h"
#include "gtkintl.h"
/* NB: please do not add backend-specific GDK headers here. This should
@@ -74,7 +75,7 @@
* ## Automatic resources ## {#automatic-resources}
*
* #GtkApplication will automatically load menus from the #GtkBuilder
* file located at "gtk/menus.ui", relative to the application's
* resource located at "gtk/menus.ui", relative to the application's
* resource base path (see g_application_set_resource_base_path()). The
* menu with the ID "app-menu" is taken as the application's app menu
* and the menu with the ID "menubar" is taken as the application's
@@ -82,7 +83,7 @@
* and accessed via gtk_application_get_menu_by_id() which allows for
* dynamic population of a part of the menu structure.
*
* If the files "gtk/menus-appmenu.ui" or "gtk/menus-traditional.ui" are
* If the resources "gtk/menus-appmenu.ui" or "gtk/menus-traditional.ui" are
* present then these files will be used in preference, depending on the
* value of gtk_application_prefers_app_menu().
*
@@ -95,6 +96,12 @@
* resources. See gtk_icon_theme_add_resource_path() for more
* information.
*
* If there is a resource located at "gtk/help-overlay.ui" which is
* defining a #GtkShortcutsWindow with ID "help_overlay" then GtkApplication
* will associate an instance of this shortcuts window with each
* #GtkApplicationWindow and set up accelerators Control-F1 and Control-?
* to open it.
*
* ## A simple application ## {#gtkapplication}
*
* [A simple example](https://git.gnome.org/browse/gtk+/tree/examples/bp/bloatpad.c)
@@ -485,9 +492,10 @@ struct _GtkApplicationPrivate
Accels accels;
guint last_window_id;
gboolean register_session;
gboolean register_session;
GtkActionMuxer *muxer;
GtkBuilder *menus_builder;
gchar *help_overlay_path;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
@@ -588,6 +596,22 @@ gtk_application_load_resources (GtkApplication *application)
gtk_application_set_menubar (application, G_MENU_MODEL (menu));
}
}
/* Help overlay */
{
gchar *path;
path = g_strconcat (base_path, "/gtk/help-overlay.ui", NULL);
if (g_resources_get_info (path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL))
{
const gchar * const accels[] = { "<Primary>F1", "<Primary>question", NULL };
application->priv->help_overlay_path = path;
gtk_application_set_accels_for_action (application, "win.show-help-overlay", accels);
}
else
g_free (path);
}
}
@@ -698,7 +722,21 @@ gtk_application_window_added (GtkApplication *application,
GtkApplicationPrivate *priv = application->priv;
if (GTK_IS_APPLICATION_WINDOW (window))
gtk_application_window_set_id (GTK_APPLICATION_WINDOW (window), ++application->priv->last_window_id);
{
gtk_application_window_set_id (GTK_APPLICATION_WINDOW (window), ++priv->last_window_id);
if (priv->help_overlay_path)
{
GtkBuilder *builder;
GtkWidget *help_overlay;
builder = gtk_builder_new_from_resource (priv->help_overlay_path);
help_overlay = GTK_WIDGET (gtk_builder_get_object (builder, "help_overlay"));
if (GTK_IS_SHORTCUTS_WINDOW (help_overlay))
gtk_application_window_set_help_overlay (GTK_APPLICATION_WINDOW (window),
GTK_SHORTCUTS_WINDOW (help_overlay));
g_object_unref (builder);
}
}
priv->windows = g_list_prepend (priv->windows, window);
gtk_window_set_application (window, application);
@@ -708,9 +746,10 @@ gtk_application_window_added (GtkApplication *application,
G_CALLBACK (gtk_application_focus_in_event_cb),
application);
gtk_application_impl_window_added (application->priv->impl, window);
gtk_application_impl_window_added (priv->impl, window);
gtk_application_impl_active_window_changed (priv->impl, window);
gtk_application_impl_active_window_changed (application->priv->impl, window);
g_object_notify_by_pspec (G_OBJECT (application), gtk_application_props[PROP_ACTIVE_WINDOW]);
}
@@ -870,8 +909,9 @@ gtk_application_finalize (GObject *object)
accels_finalize (&application->priv->accels);
G_OBJECT_CLASS (gtk_application_parent_class)
->finalize (object);
g_free (application->priv->help_overlay_path);
G_OBJECT_CLASS (gtk_application_parent_class)->finalize (object);
}
static void

View File

@@ -228,6 +228,8 @@ struct _GtkApplicationWindowPrivate
GMenu *menubar_section;
guint id;
GtkShortcutsWindow *help_overlay;
};
static void
@@ -788,9 +790,9 @@ gtk_application_window_dispose (GObject *object)
g_clear_object (&window->priv->app_menu_section);
g_clear_object (&window->priv->menubar_section);
g_clear_object (&window->priv->help_overlay);
G_OBJECT_CLASS (gtk_application_window_parent_class)
->dispose (object);
G_OBJECT_CLASS (gtk_application_window_parent_class)->dispose (object);
/* We do this below the chain-up above to give us a chance to be
* removed from the GtkApplication (which is done in the dispose
@@ -959,3 +961,75 @@ gtk_application_window_set_id (GtkApplicationWindow *window,
g_return_if_fail (GTK_IS_APPLICATION_WINDOW (window));
window->priv->id = id;
}
static void
show_help_overlay (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkApplicationWindow *window = user_data;
if (window->priv->help_overlay)
gtk_widget_show (GTK_WIDGET (window->priv->help_overlay));
}
/**
* gtk_application_window_set_help_overlay:
* @window: a #GtkApplicationWindow
* @help_overlay: a #GtkShortcutsWindow
*
* Associates a shortcuts window with the application window, and
* sets up a action with the name win.show-help-overay to present
* it.
*
* Since: 3.20
*/
void
gtk_application_window_set_help_overlay (GtkApplicationWindow *window,
GtkShortcutsWindow *help_overlay)
{
g_return_if_fail (GTK_IS_APPLICATION_WINDOW (window));
g_return_if_fail (help_overlay == NULL || GTK_IS_SHORTCUTS_WINDOW (help_overlay));
if (window->priv->help_overlay)
g_signal_handlers_disconnect_by_func (window->priv->help_overlay,
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
g_set_object (&window->priv->help_overlay, help_overlay);
if (!window->priv->help_overlay)
return;
gtk_window_set_modal (GTK_WINDOW (help_overlay), TRUE);
gtk_window_set_transient_for (GTK_WINDOW (help_overlay), GTK_WINDOW (window));
g_signal_connect (help_overlay, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
if (!g_action_map_lookup_action (G_ACTION_MAP (window->priv->actions), "show-help-overlay"))
{
GSimpleAction *action;
action = g_simple_action_new ("show-help-overlay", NULL);
g_signal_connect (action, "activate", G_CALLBACK (show_help_overlay), window);
g_action_map_add_action (G_ACTION_MAP (window->priv->actions), G_ACTION (action));
}
}
/**
* gtk_application_window_get_help_overlay:
* @window: a #GtkApplicationWindow
*
* Gets the #GtkShortcutsWindow that has been set up with
* a prior call to gtk_application_window_set_help_overlay().
*
* Returns: the help overlay associated with @window, or %NULL
*
* Since: 3.20
*/
GtkShortcutsWindow *
gtk_application_window_get_help_overlay (GtkApplicationWindow *window)
{
g_return_val_if_fail (GTK_IS_APPLICATION_WINDOW (window), NULL);
return window->priv->help_overlay;
}

View File

@@ -25,6 +25,7 @@
#endif
#include <gtk/gtkwindow.h>
#include <gtk/gtkshortcutswindow.h>
G_BEGIN_DECLS
@@ -78,6 +79,13 @@ gboolean gtk_application_window_get_show_menubar (GtkApplicationWindow *windo
GDK_AVAILABLE_IN_3_6
guint gtk_application_window_get_id (GtkApplicationWindow *window);
GDK_AVAILABLE_IN_3_20
void gtk_application_window_set_help_overlay (GtkApplicationWindow *window,
GtkShortcutsWindow *help_overlay);
GDK_AVAILABLE_IN_3_20
GtkShortcutsWindow *
gtk_application_window_get_help_overlay (GtkApplicationWindow *window);
G_END_DECLS
#endif /* __GTK_APPLICATION_WINDOW_H__ */

View File

@@ -478,7 +478,8 @@ gtk_builder_get_parameters (GtkBuilder *builder,
parameter.name = prop->pspec->name;
if (G_IS_PARAM_SPEC_OBJECT (prop->pspec) &&
(G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != GDK_TYPE_PIXBUF))
(G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != GDK_TYPE_PIXBUF) &&
(G_PARAM_SPEC_VALUE_TYPE (prop->pspec) != G_TYPE_FILE))
{
GObject *object = g_hash_table_lookup (builder->priv->objects,
prop->text->str);
@@ -2035,6 +2036,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
}
break;
case G_TYPE_OBJECT:
case G_TYPE_INTERFACE:
if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF))
{
gchar *filename;
@@ -2093,6 +2095,27 @@ G_GNUC_END_IGNORE_DEPRECATIONS
g_free (filename);
ret = TRUE;
}
else if (G_VALUE_HOLDS (value, G_TYPE_FILE))
{
GFile *file;
if (g_hash_table_contains (builder->priv->objects, string))
{
g_set_error (error,
GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_VALUE,
"Could not create file '%s': "
" '%s' is already used as object id",
string, string);
return FALSE;
}
file = g_file_new_for_uri (string);
g_value_set_object (value, file);
g_object_unref (G_OBJECT (file));
ret = TRUE;
}
else

314
gtk/gtkshortcutlabel.c Normal file
View File

@@ -0,0 +1,314 @@
/* gtkshortcutlabel.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkshortcutlabelprivate.h"
#include "gtklabel.h"
#include "gtkframe.h"
#include "gtkstylecontext.h"
#include "gtkprivate.h"
#include "gtkintl.h"
struct _GtkShortcutLabel
{
GtkBox parent_instance;
gchar *accelerator;
};
struct _GtkShortcutLabelClass
{
GtkBoxClass parent_class;
};
G_DEFINE_TYPE (GtkShortcutLabel, gtk_shortcut_label, GTK_TYPE_BOX)
enum {
PROP_0,
PROP_ACCELERATOR,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP];
static gchar **
get_labels (guint key, GdkModifierType modifier, guint *n_mods)
{
const gchar *labels[16];
gchar key_label[6];
gchar *tmp;
gunichar ch;
gint i = 0;
if (modifier & GDK_SHIFT_MASK)
labels[i++] = C_("keyboard label", "Shift");
if (modifier & GDK_CONTROL_MASK)
labels[i++] = C_("keyboard label", "Ctrl");
if (modifier & GDK_MOD1_MASK)
labels[i++] = C_("keyboard label", "Alt");
if (modifier & GDK_MOD2_MASK)
labels[i++] = "Mod2";
if (modifier & GDK_MOD3_MASK)
labels[i++] = "Mod3";
if (modifier & GDK_MOD4_MASK)
labels[i++] = "Mod4";
if (modifier & GDK_MOD5_MASK)
labels[i++] = "Mod5";
if (modifier & GDK_SUPER_MASK)
labels[i++] = C_("keyboard label", "Super");
if (modifier & GDK_HYPER_MASK)
labels[i++] = C_("keyboard label", "Hyper");
if (modifier & GDK_META_MASK)
labels[i++] = C_("keyboard label", "Meta");
*n_mods = i;
ch = gdk_keyval_to_unicode (key);
if (ch && ch < 0x80 && g_unichar_isgraph (ch))
{
switch (ch)
{
case '\\':
labels[i++] = C_("keyboard label", "Backslash");
break;
default:
memset (key_label, 0, 6);
g_unichar_to_utf8 (g_unichar_toupper (ch), key_label);
labels[i++] = key_label;
break;
}
}
else
{
switch (key)
{
case GDK_KEY_Left:
labels[i++] = "\xe2\x86\x90";
break;
case GDK_KEY_Up:
labels[i++] = "\xe2\x86\x91";
break;
case GDK_KEY_Right:
labels[i++] = "\xe2\x86\x92";
break;
case GDK_KEY_Down:
labels[i++] = "\xe2\x86\x93";
break;
case GDK_KEY_space:
labels[i++] = "\xe2\x90\xa3";
break;
case GDK_KEY_Return:
labels[i++] = "\xe2\x8f\x8e";
break;
case GDK_KEY_Page_Up:
labels[i++] = C_("keyboard label", "Page_Up");
break;
case GDK_KEY_Page_Down:
labels[i++] = C_("keyboard label", "Page_Down");
break;
default:
tmp = gdk_keyval_name (gdk_keyval_to_lower (key));
if (tmp != NULL)
{
if (tmp[0] != 0 && tmp[1] == 0)
{
key_label[0] = g_ascii_toupper (tmp[0]);
key_label[1] = '\0';
labels[i++] = key_label;
}
else
{
labels[i++] = g_dpgettext2 (GETTEXT_PACKAGE, "keyboard label", tmp);
}
}
}
}
labels[i] = NULL;
return g_strdupv ((gchar **)labels);
}
static GtkWidget *
dim_label (const gchar *text)
{
GtkWidget *label;
label = gtk_label_new (text);
gtk_widget_show (label);
gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
return label;
}
static void
gtk_shortcut_label_rebuild (GtkShortcutLabel *self)
{
gchar **accels = NULL;
gchar **keys = NULL;
GdkModifierType modifier = 0;
guint key = 0;
guint i, k;
guint n_mods;
gtk_container_foreach (GTK_CONTAINER (self), (GtkCallback)gtk_widget_destroy, NULL);
if (self->accelerator == NULL)
return;
accels = g_strsplit (self->accelerator, " ", 0);
for (k = 0; accels[k]; k++)
{
gtk_accelerator_parse (accels[k], &key, &modifier);
if ((key == 0) && (modifier == 0))
{
g_warning ("Failed to parse accelerator '%s'", self->accelerator);
goto out;
}
if (k > 0)
gtk_container_add (GTK_CONTAINER (self), dim_label ("/"));
keys = get_labels (key, modifier, &n_mods);
for (i = 0; keys[i]; i++)
{
GtkWidget *frame;
GtkWidget *disp;
if (i > 0)
gtk_container_add (GTK_CONTAINER (self), dim_label ("+"));
frame = gtk_frame_new (NULL);
gtk_widget_show (frame);
gtk_container_add (GTK_CONTAINER (self), frame);
if (i < n_mods)
gtk_widget_set_size_request (frame, 50, -1);
disp = gtk_label_new (keys[i]);
gtk_widget_show (disp);
gtk_container_add (GTK_CONTAINER (frame), disp);
}
g_strfreev (keys);
}
out:
g_strfreev (accels);
}
static void
gtk_shortcut_label_finalize (GObject *object)
{
GtkShortcutLabel *self = (GtkShortcutLabel *)object;
g_free (self->accelerator);
G_OBJECT_CLASS (gtk_shortcut_label_parent_class)->finalize (object);
}
static void
gtk_shortcut_label_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkShortcutLabel *self = GTK_SHORTCUT_LABEL (object);
switch (prop_id)
{
case PROP_ACCELERATOR:
g_value_set_string (value, gtk_shortcut_label_get_accelerator (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcut_label_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkShortcutLabel *self = GTK_SHORTCUT_LABEL (object);
switch (prop_id)
{
case PROP_ACCELERATOR:
gtk_shortcut_label_set_accelerator (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcut_label_class_init (GtkShortcutLabelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_shortcut_label_finalize;
object_class->get_property = gtk_shortcut_label_get_property;
object_class->set_property = gtk_shortcut_label_set_property;
properties[PROP_ACCELERATOR] =
g_param_spec_string ("accelerator", P_("Accelerator"), P_("Accelerator"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
static void
gtk_shortcut_label_init (GtkShortcutLabel *self)
{
gtk_box_set_spacing (GTK_BOX (self), 6);
}
GtkWidget *
gtk_shortcut_label_new (const gchar *accelerator)
{
return g_object_new (GTK_TYPE_SHORTCUT_LABEL,
"accelerator", accelerator,
NULL);
}
const gchar *
gtk_shortcut_label_get_accelerator (GtkShortcutLabel *self)
{
g_return_val_if_fail (GTK_IS_SHORTCUT_LABEL (self), NULL);
return self->accelerator;
}
void
gtk_shortcut_label_set_accelerator (GtkShortcutLabel *self,
const gchar *accelerator)
{
g_return_if_fail (GTK_IS_SHORTCUT_LABEL (self));
if (g_strcmp0 (accelerator, self->accelerator) != 0)
{
g_free (self->accelerator);
self->accelerator = g_strdup (accelerator);
gtk_shortcut_label_rebuild (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACCELERATOR]);
}
}

View File

@@ -0,0 +1,47 @@
/* gtkshortcutlabelprivate.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_SHORTCUT_LABEL_H__
#define __GTK_SHORTCUT_LABEL_H__
#include <gtk/gtkbox.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHORTCUT_LABEL (gtk_shortcut_label_get_type())
#define GTK_SHORTCUT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SHORTCUT_LABEL, GtkShortcutLabel))
#define GTK_SHORTCUT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SHORTCUT_LABEL, GtkShortcutLabelClass))
#define GTK_IS_SHORTCUT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SHORTCUT_LABEL))
#define GTK_IS_SHORTCUT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SHORTCUT_LABEL))
#define GTK_SHORTCUT_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SHORTCUT_LABEL, GtkShortcutLabelClass))
typedef struct _GtkShortcutLabel GtkShortcutLabel;
typedef struct _GtkShortcutLabelClass GtkShortcutLabelClass;
GType gtk_shortcut_label_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_shortcut_label_new (const gchar *accelerator);
const gchar *gtk_shortcut_label_get_accelerator (GtkShortcutLabel *self);
void gtk_shortcut_label_set_accelerator (GtkShortcutLabel *self,
const gchar *accelerator);
G_END_DECLS
#endif /* __GTK_SHORTCUT_LABEL_H__ */

311
gtk/gtkshortcutsgesture.c Normal file
View File

@@ -0,0 +1,311 @@
/* gtkshortcutsgesture.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkshortcutsgesture.h"
#include "gtkimage.h"
#include "gtklabel.h"
#include "gtksizegroup.h"
#include "gtkorientable.h"
#include "gtkstylecontext.h"
#include "gtkprivate.h"
#include "gtkintl.h"
/**
* SECTION:gtkshortcutsgesture
* @Title: GtkShortcutsGesture
* @Short_description: Represents a gesture in a GtkShortcutsWindow
*
* A GtkShortcutsGesture represents a single gesture with an image
* an a short text.
*
* This widget is only meant to be used with #GtkShortcutsWindow.
*/
struct _GtkShortcutsGesture
{
GtkBox parent_instance;
GtkImage *image;
GtkLabel *title;
GtkLabel *subtitle;
GtkBox *title_box;
GtkSizeGroup *title_size_group;
GtkSizeGroup *icon_size_group;
};
struct _GtkShortcutsGestureClass
{
GtkBoxClass parent_class;
};
G_DEFINE_TYPE (GtkShortcutsGesture, gtk_shortcuts_gesture, GTK_TYPE_BOX)
enum {
PROP_0,
PROP_ICON,
PROP_TITLE,
PROP_SUBTITLE,
PROP_ICON_SIZE_GROUP,
PROP_TITLE_SIZE_GROUP,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP];
static void
gtk_shortcuts_gesture_set_title_size_group (GtkShortcutsGesture *self,
GtkSizeGroup *group)
{
if (self->title_size_group)
gtk_size_group_remove_widget (self->title_size_group, GTK_WIDGET (self->title_box));
if (group)
gtk_size_group_add_widget (group, GTK_WIDGET (self->title_box));
g_set_object (&self->title_size_group, group);
}
static void
gtk_shortcuts_gesture_set_icon_size_group (GtkShortcutsGesture *self,
GtkSizeGroup *group)
{
if (self->icon_size_group)
gtk_size_group_remove_widget (self->icon_size_group, GTK_WIDGET (self->image));
if (group)
gtk_size_group_add_widget (group, GTK_WIDGET (self->image));
g_set_object (&self->icon_size_group, group);
}
static void
gtk_shortcuts_gesture_set_icon (GtkShortcutsGesture *self,
GIcon *gicon)
{
gtk_image_set_from_gicon (self->image, gicon, GTK_ICON_SIZE_DIALOG);
}
static void
gtk_shortcuts_gesture_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkShortcutsGesture *self = GTK_SHORTCUTS_GESTURE (object);
switch (prop_id)
{
case PROP_ICON:
{
GIcon *icon;
gtk_image_get_gicon (self->image, &icon, NULL);
g_value_set_object (value, icon);
}
break;
case PROP_TITLE:
g_value_set_string (value, gtk_label_get_label (self->title));
break;
case PROP_SUBTITLE:
g_value_set_string (value, gtk_label_get_label (self->subtitle));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_gesture_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkShortcutsGesture *self = GTK_SHORTCUTS_GESTURE (object);
switch (prop_id)
{
case PROP_ICON:
gtk_shortcuts_gesture_set_icon (self, g_value_get_object (value));
break;
case PROP_TITLE:
gtk_label_set_label (self->title, g_value_get_string (value));
break;
case PROP_SUBTITLE:
gtk_label_set_label (self->subtitle, g_value_get_string (value));
break;
case PROP_TITLE_SIZE_GROUP:
gtk_shortcuts_gesture_set_title_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
break;
case PROP_ICON_SIZE_GROUP:
gtk_shortcuts_gesture_set_icon_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_gesture_finalize (GObject *object)
{
GtkShortcutsGesture *self = GTK_SHORTCUTS_GESTURE (object);
g_clear_object (&self->title_size_group);
g_clear_object (&self->icon_size_group);
G_OBJECT_CLASS (gtk_shortcuts_gesture_parent_class)->finalize (object);
}
static void
gtk_shortcuts_gesture_add (GtkContainer *container,
GtkWidget *widget)
{
g_warning ("Can't add children to %s", G_OBJECT_TYPE_NAME (container));
}
static GType
gtk_shortcuts_gesture_child_type (GtkContainer *container)
{
return G_TYPE_NONE;
}
static void
gtk_shortcuts_gesture_class_init (GtkShortcutsGestureClass *klass)
{
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_shortcuts_gesture_finalize;
object_class->get_property = gtk_shortcuts_gesture_get_property;
object_class->set_property = gtk_shortcuts_gesture_set_property;
container_class->add = gtk_shortcuts_gesture_add;
container_class->child_type = gtk_shortcuts_gesture_child_type;
/**
* GtkShortcutsGesture:icon:
*
* The icon used to represent the gesture.
*/
properties[PROP_ICON] =
g_param_spec_object ("icon",
P_("Icon"),
P_("Icon"),
G_TYPE_ICON,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsGesture:title:
*
* The title for the gesture.
*
* This should be a short, one-line text that describes the action
* associated with the gesture.
*/
properties[PROP_TITLE] =
g_param_spec_string ("title",
P_("Title"),
P_("Title"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsGesture:subtitle:
*
* The subtitle for the gesture.
*
* This should be a short, one-line text that describes the gesture
* itself, e.g. "Two-finger swipe".
*/
properties[PROP_SUBTITLE] =
g_param_spec_string ("subtitle",
P_("Subtitle"),
P_("Subtitle"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsGesture:title-size-group:
*
* The size group for the textual portion of this gesture.
*
* This is used internally by GTK+, and must not be modified by applications.
*/
properties[PROP_TITLE_SIZE_GROUP] =
g_param_spec_object ("title-size-group",
P_("Title Size Group"),
P_("Title Size Group"),
GTK_TYPE_SIZE_GROUP,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsShortcut:icon-size-group:
*
* The size group for the image portion of this gesture.
*
* This is used internally by GTK+, and must not be modified by applications.
*/
properties[PROP_ICON_SIZE_GROUP] =
g_param_spec_object ("icon-size-group",
P_("Icon Size Group"),
P_("Icon Size Group"),
GTK_TYPE_SIZE_GROUP,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
static void
gtk_shortcuts_gesture_init (GtkShortcutsGesture *self)
{
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL);
gtk_box_set_spacing (GTK_BOX (self), 12);
self->image = g_object_new (GTK_TYPE_IMAGE,
"visible", TRUE,
NULL);
GTK_CONTAINER_CLASS (gtk_shortcuts_gesture_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (self->image));
self->title_box = g_object_new (GTK_TYPE_BOX,
"hexpand", TRUE,
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
GTK_CONTAINER_CLASS (gtk_shortcuts_gesture_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (self->title_box));
self->title = g_object_new (GTK_TYPE_LABEL,
"visible", TRUE,
"xalign", 0.0f,
NULL);
gtk_container_add (GTK_CONTAINER (self->title_box), GTK_WIDGET (self->title));
self->subtitle = g_object_new (GTK_TYPE_LABEL,
"visible", TRUE,
"xalign", 0.0f,
NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self->subtitle)),
"dim-label");
gtk_container_add (GTK_CONTAINER (self->title_box), GTK_WIDGET (self->subtitle));
}

42
gtk/gtkshortcutsgesture.h Normal file
View File

@@ -0,0 +1,42 @@
/* gtkshortcutsgestureprivate.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_SHORTCUTS_GESTURE_H__
#define __GTK_SHORTCUTS_GESTURE_H__
#include <gtk/gtkbox.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHORTCUTS_GESTURE (gtk_shortcuts_gesture_get_type())
#define GTK_SHORTCUTS_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SHORTCUTS_GESTURE, GtkShortcutsGesture))
#define GTK_SHORTCUTS_GESTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SHORTCUTS_GESTURE, GtkShortcutsGestureClass))
#define GTK_IS_SHORTCUTS_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SHORTCUTS_GESTURE))
#define GTK_IS_SHORTCUTS_GESTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SHORTCUTS_GESTURE))
#define GTK_SHORTCUTS_GESTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SHORTCUTS_GESTURE, GtkShortcutsGestureClass))
typedef struct _GtkShortcutsGesture GtkShortcutsGesture;
typedef struct _GtkShortcutsGestureClass GtkShortcutsGestureClass;
GDK_AVAILABLE_IN_3_20
GType gtk_shortcuts_gesture_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GTK_SHORTCUTS_GESTURE_H__ */

306
gtk/gtkshortcutsgroup.c Normal file
View File

@@ -0,0 +1,306 @@
/* gtkshortcutsgroup.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkshortcutsgroup.h"
#include "gtkshortcutsshortcut.h"
#include "gtkshortcutsgesture.h"
#include "gtklabel.h"
#include "gtkorientable.h"
#include "gtksizegroup.h"
#include "gtkprivate.h"
#include "gtkintl.h"
/**
* SECTION:gtkshortcutsgroup
* @Title: GtkShortcutsGroup
* @Short_description: Represents a group of shortcuts in a GtkShortcutsWindow
*
* A GtkShortcutsGroup represents a group of related keyboard shortcuts
* or gestures. The group has a title. It may optionally be associated with
* a view of the application, which can be used to show only relevant shortcuts
* depending on the application context.
*
* This widget is only meant to be used with #GtkShortcutsWindow.
*/
struct _GtkShortcutsGroup
{
GtkBox parent_instance;
GtkLabel *title;
gchar *view;
guint height;
};
struct _GtkShortcutsGroupClass
{
GtkBoxClass parent_class;
};
G_DEFINE_TYPE (GtkShortcutsGroup, gtk_shortcuts_group, GTK_TYPE_BOX)
enum {
PROP_0,
PROP_TITLE,
PROP_VIEW,
PROP_ACCEL_SIZE_GROUP,
PROP_TITLE_SIZE_GROUP,
PROP_HEIGHT,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP];
static void
gtk_shortcuts_group_set_accel_size_group (GtkShortcutsGroup *group,
GtkSizeGroup *size_group)
{
GList *children, *l;
children = gtk_container_get_children (GTK_CONTAINER (group));
for (l = children; l; l = l->next)
{
if (GTK_IS_SHORTCUTS_SHORTCUT (l->data))
g_object_set (l->data, "accel-size-group", size_group, NULL);
else if (GTK_IS_SHORTCUTS_GESTURE (l->data))
g_object_set (l->data, "icon-size-group", size_group, NULL);
}
g_list_free (children);
}
static void
gtk_shortcuts_group_set_title_size_group (GtkShortcutsGroup *group,
GtkSizeGroup *size_group)
{
GList *children, *l;
children = gtk_container_get_children (GTK_CONTAINER (group));
for (l = children; l; l = l->next)
{
if (GTK_IS_SHORTCUTS_SHORTCUT (l->data))
g_object_set (l->data, "title-size-group", size_group, NULL);
else if (GTK_IS_SHORTCUTS_GESTURE (l->data))
g_object_set (l->data, "title-size-group", size_group, NULL);
}
g_list_free (children);
}
static guint
gtk_shortcuts_group_get_height (GtkShortcutsGroup *group)
{
GList *children, *l;
guint height;
height = 1;
children = gtk_container_get_children (GTK_CONTAINER (group));
for (l = children; l; l = l->next)
{
if (GTK_IS_SHORTCUTS_SHORTCUT (l->data))
height += 1;
else if (GTK_IS_SHORTCUTS_GESTURE (l->data))
height += 2;
}
g_list_free (children);
return height;
}
static void
gtk_shortcuts_group_add (GtkContainer *container,
GtkWidget *widget)
{
if (GTK_IS_SHORTCUTS_SHORTCUT (widget) ||
GTK_IS_SHORTCUTS_GESTURE (widget))
GTK_CONTAINER_CLASS (gtk_shortcuts_group_parent_class)->add (container, widget);
else
g_warning ("Can't add children of type %s to %s",
G_OBJECT_TYPE_NAME (widget),
G_OBJECT_TYPE_NAME (container));
}
static void
gtk_shortcuts_group_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkShortcutsGroup *self = GTK_SHORTCUTS_GROUP (object);
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, gtk_label_get_label (self->title));
break;
case PROP_VIEW:
g_value_set_string (value, self->view);
break;
case PROP_HEIGHT:
g_value_set_uint (value, gtk_shortcuts_group_get_height (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_group_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkShortcutsGroup *self = GTK_SHORTCUTS_GROUP (object);
switch (prop_id)
{
case PROP_TITLE:
gtk_label_set_label (self->title, g_value_get_string (value));
break;
case PROP_VIEW:
g_free (self->view);
self->view = g_value_dup_string (value);
break;
case PROP_ACCEL_SIZE_GROUP:
gtk_shortcuts_group_set_accel_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
break;
case PROP_TITLE_SIZE_GROUP:
gtk_shortcuts_group_set_title_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_group_finalize (GObject *object)
{
GtkShortcutsGroup *self = GTK_SHORTCUTS_GROUP (object);
g_free (self->view);
G_OBJECT_CLASS (gtk_shortcuts_group_parent_class)->finalize (object);
}
static void
gtk_shortcuts_group_class_init (GtkShortcutsGroupClass *klass)
{
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_shortcuts_group_finalize;
object_class->get_property = gtk_shortcuts_group_get_property;
object_class->set_property = gtk_shortcuts_group_set_property;
container_class->add = gtk_shortcuts_group_add;
/**
* GtkShortcutsGroup:title:
*
* The title for this group of shortcuts.
*/
properties[PROP_TITLE] =
g_param_spec_string ("title", P_("Title"), P_("Title"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsGroup:view:
*
* An optional view that the shortcuts in this group are relevant for.
* The group will be hidden if the #GtkShortcutsWindow:view-name property
* does not match the view of this group.
*
* Set this to %NULL to make the group always visible.
*/
properties[PROP_VIEW] =
g_param_spec_string ("view", P_("View"), P_("View"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsGroup:accel-size-group:
*
* The size group for the accelerator portion of shortcuts in this group.
*
* This is used internally by GTK+, and must not be modified by applications.
*/
properties[PROP_ACCEL_SIZE_GROUP] =
g_param_spec_object ("accel-size-group",
P_("Accelerator Size Group"),
P_("Accelerator Size Group"),
GTK_TYPE_SIZE_GROUP,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsGroup:title-size-group:
*
* The size group for the textual portion of shortcuts in this group.
*
* This is used internally by GTK+, and must not be modified by applications.
*/
properties[PROP_TITLE_SIZE_GROUP] =
g_param_spec_object ("title-size-group",
P_("Title Size Group"),
P_("Title Size Group"),
GTK_TYPE_SIZE_GROUP,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsGroup:height:
*
* A rough measure for the number of lines in this group.
*
* This is used internally by GTK+, and is not useful for applications.
*/
properties[PROP_HEIGHT] =
g_param_spec_uint ("height", P_("Height"), P_("Height"),
0, G_MAXUINT, 0,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
static void
gtk_shortcuts_group_init (GtkShortcutsGroup *self)
{
PangoAttrList *attrs;
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
gtk_box_set_spacing (GTK_BOX (self), 10);
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
self->title = g_object_new (GTK_TYPE_LABEL,
"attributes", attrs,
"visible", TRUE,
"xalign", 0.0f,
NULL);
pango_attr_list_unref (attrs);
GTK_CONTAINER_CLASS (gtk_shortcuts_group_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (self->title));
}

42
gtk/gtkshortcutsgroup.h Normal file
View File

@@ -0,0 +1,42 @@
/* gtkshortcutsgroupprivate.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_SHORTCUTS_GROUP_H__
#define __GTK_SHORTCUTS_GROUP_H__
#include <gtk/gtkbox.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHORTCUTS_GROUP (gtk_shortcuts_group_get_type ())
#define GTK_SHORTCUTS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SHORTCUTS_GROUP, GtkShortcutsGroup))
#define GTK_SHORTCUTS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SHORTCUTS_GROUP, GtkShortcutsGroupClass))
#define GTK_IS_SHORTCUTS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SHORTCUTS_GROUP))
#define GTK_IS_SHORTCUTS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SHORTCUTS_GROUP))
#define GTK_SHORTCUTS_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SHORTCUTS_GROUP, GtkShortcutsGroupClass))
typedef struct _GtkShortcutsGroup GtkShortcutsGroup;
typedef struct _GtkShortcutsGroupClass GtkShortcutsGroupClass;
GDK_AVAILABLE_IN_3_20
GType gtk_shortcuts_group_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GTK_SHORTCUTS_GROUP_H__ */

716
gtk/gtkshortcutssection.c Normal file
View File

@@ -0,0 +1,716 @@
/* gtkshortcutssection.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkshortcutssection.h"
#include "gtkshortcutsgroup.h"
#include "gtkbutton.h"
#include "gtklabel.h"
#include "gtkstack.h"
#include "gtkstackswitcher.h"
#include "gtkstylecontext.h"
#include "gtkorientable.h"
#include "gtksizegroup.h"
#include "gtkwidget.h"
#include "gtkbindings.h"
#include "gtkprivate.h"
#include "gtkmarshalers.h"
#include "gtkgesturepan.h"
#include "gtkintl.h"
/**
* SECTION:gtkshortcutssection
* @Title: GtkShortcutsSection
* @Short_description: Represents an application mode in a GtkShortcutsWindow
*
* A GtkShortcutsSection collects all the keyboard shortcuts and gestures
* for a major application mode. If your application needs multiple sections,
* you should give each section a unique #GtkShortcutsSection:section-name and
* a #GtkShortcutsSection:title that can be shown in the section selector of
* the GtkShortcutsWindow.
*
* The #GtkShortcutsSection:max-height property can be used to influence how
* the groups in the section are distributed over pages and columns.
*
* This widget is only meant to be used with #GtkShortcutsWindow.
*/
struct _GtkShortcutsSection
{
GtkBox parent_instance;
gchar *name;
gchar *title;
gchar *view_name;
guint max_height;
GtkStack *stack;
GtkStackSwitcher *switcher;
GtkWidget *show_all;
gboolean has_filtered_group;
gboolean need_reflow;
GtkGesture *pan_gesture;
};
struct _GtkShortcutsSectionClass
{
GtkBoxClass parent_class;
gboolean (* change_current_page) (GtkShortcutsSection *self,
gint offset);
};
G_DEFINE_TYPE (GtkShortcutsSection, gtk_shortcuts_section, GTK_TYPE_BOX)
enum {
PROP_0,
PROP_TITLE,
PROP_SECTION_NAME,
PROP_VIEW_NAME,
PROP_MAX_HEIGHT,
LAST_PROP
};
enum {
CHANGE_CURRENT_PAGE,
LAST_SIGNAL
};
static GParamSpec *properties[LAST_PROP];
static guint signals[LAST_SIGNAL];
static void gtk_shortcuts_section_set_view_name (GtkShortcutsSection *self,
const gchar *view_name);
static void gtk_shortcuts_section_add_group (GtkShortcutsSection *self,
GtkShortcutsGroup *group);
static void gtk_shortcuts_section_show_all (GtkShortcutsSection *self);
static void gtk_shortcuts_section_filter_groups (GtkShortcutsSection *self);
static void gtk_shortcuts_section_reflow_groups (GtkShortcutsSection *self);
static void gtk_shortcuts_section_maybe_reflow (GtkShortcutsSection *self);
static gboolean gtk_shortcuts_section_change_current_page (GtkShortcutsSection *self,
gint offset);
static void gtk_shortcuts_section_pan_gesture_pan (GtkGesturePan *gesture,
GtkPanDirection direction,
gdouble offset,
GtkShortcutsSection *self);
static void
gtk_shortcuts_section_map (GtkWidget *widget)
{
GtkShortcutsSection *self = GTK_SHORTCUTS_SECTION (widget);
if (self->need_reflow)
gtk_shortcuts_section_reflow_groups (self);
GTK_WIDGET_CLASS (gtk_shortcuts_section_parent_class)->map (widget);
}
static void
gtk_shortcuts_section_add (GtkContainer *container,
GtkWidget *child)
{
GtkShortcutsSection *self = GTK_SHORTCUTS_SECTION (container);
if (GTK_IS_SHORTCUTS_GROUP (child))
gtk_shortcuts_section_add_group (self, GTK_SHORTCUTS_GROUP (child));
else
g_warning ("Can't add children of type %s to %s",
G_OBJECT_TYPE_NAME (child),
G_OBJECT_TYPE_NAME (container));
}
static void
gtk_shortcuts_section_finalize (GObject *object)
{
GtkShortcutsSection *self = (GtkShortcutsSection *)object;
g_clear_pointer (&self->name, g_free);
g_clear_pointer (&self->title, g_free);
g_clear_object (&self->pan_gesture);
G_OBJECT_CLASS (gtk_shortcuts_section_parent_class)->finalize (object);
}
static void
gtk_shortcuts_section_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkShortcutsSection *self = (GtkShortcutsSection *)object;
switch (prop_id)
{
case PROP_SECTION_NAME:
g_value_set_string (value, self->name);
break;
case PROP_VIEW_NAME:
g_value_set_string (value, self->view_name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_MAX_HEIGHT:
g_value_set_uint (value, self->max_height);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_section_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkShortcutsSection *self = (GtkShortcutsSection *)object;
switch (prop_id)
{
case PROP_SECTION_NAME:
g_free (self->name);
self->name = g_value_dup_string (value);
break;
case PROP_VIEW_NAME:
gtk_shortcuts_section_set_view_name (self, g_value_get_string (value));
break;
case PROP_TITLE:
g_free (self->title);
self->title = g_value_dup_string (value);
break;
case PROP_MAX_HEIGHT:
self->max_height = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static GType
gtk_shortcuts_section_child_type (GtkContainer *container)
{
return GTK_TYPE_SHORTCUTS_GROUP;
}
static void
gtk_shortcuts_section_class_init (GtkShortcutsSectionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
GtkBindingSet *binding_set;
object_class->finalize = gtk_shortcuts_section_finalize;
object_class->get_property = gtk_shortcuts_section_get_property;
object_class->set_property = gtk_shortcuts_section_set_property;
widget_class->map = gtk_shortcuts_section_map;
container_class->add = gtk_shortcuts_section_add;
container_class->child_type = gtk_shortcuts_section_child_type;
klass->change_current_page = gtk_shortcuts_section_change_current_page;
/**
* GtkShortcutsSection:section-name:
*
* A unique name to identify this section among the sections
* added to the GtkShortcutsWindow. Setting the #GtkShortcutsWindow:section-name
* property to this string will make this section shown in the
* GtkShortcutsWindow.
*/
properties[PROP_SECTION_NAME] =
g_param_spec_string ("section-name", P_("Section Name"), P_("Section Name"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsSection:view-name:
*
* A view name to filter the groups in this section by.
* See #GtkShortcutsGroup:view.
*
* Applications are expected to use the #GtkShortcutsWindow:view-name
* property for this purpose.
*/
properties[PROP_VIEW_NAME] =
g_param_spec_string ("view-name", P_("View Name"), P_("View Name"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsSection:title:
*
* The string to show in the section selector of the GtkShortcutsWindow
* for this section. If there is only one section, you don't need to
* set a title, since the section selector will not be shown in this case.
*/
properties[PROP_TITLE] =
g_param_spec_string ("title", P_("Title"), P_("Title"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsSection:max-height:
*
* The maximum number of lines to allow per column. This property can
* be used to influence how the groups in this section are distributed
* across pages and columns. The default value of 15 should work in
* for most cases.
*/
properties[PROP_MAX_HEIGHT] =
g_param_spec_uint ("max-height", P_("Maximum Height"), P_("Maximum Height"),
0, G_MAXUINT, 15,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
signals[CHANGE_CURRENT_PAGE] =
g_signal_new (I_("change-current-page"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkShortcutsSectionClass, change_current_page),
NULL, NULL,
_gtk_marshal_BOOLEAN__INT,
G_TYPE_BOOLEAN, 1,
G_TYPE_INT);
binding_set = gtk_binding_set_by_class (klass);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_Page_Up, 0,
"change-current-page", 1,
G_TYPE_INT, -1);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_Page_Down, 0,
"change-current-page", 1,
G_TYPE_INT, 1);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_Page_Up, GDK_CONTROL_MASK,
"change-current-page", 1,
G_TYPE_INT, -1);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_Page_Down, GDK_CONTROL_MASK,
"change-current-page", 1,
G_TYPE_INT, 1);
}
static void
gtk_shortcuts_section_init (GtkShortcutsSection *self)
{
GtkWidget *box;
self->max_height = 15;
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
gtk_box_set_homogeneous (GTK_BOX (self), FALSE);
gtk_box_set_spacing (GTK_BOX (self), 22);
gtk_container_set_border_width (GTK_CONTAINER (self), 24);
self->stack = g_object_new (GTK_TYPE_STACK,
"homogeneous", TRUE,
"transition-type", GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT,
"vexpand", TRUE,
"visible", TRUE,
NULL);
GTK_CONTAINER_CLASS (gtk_shortcuts_section_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (self->stack));
self->switcher = g_object_new (GTK_TYPE_STACK_SWITCHER,
"halign", GTK_ALIGN_CENTER,
"stack", self->stack,
"spacing", 12,
"no-show-all", TRUE,
NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self->switcher)), "round");
gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (self->switcher)), "linked");
self->show_all = gtk_button_new_with_mnemonic (_("_Show All"));
gtk_widget_set_no_show_all (self->show_all, TRUE);
g_signal_connect_swapped (self->show_all, "clicked",
G_CALLBACK (gtk_shortcuts_section_show_all), self);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20);
GTK_CONTAINER_CLASS (gtk_shortcuts_section_parent_class)->add (GTK_CONTAINER (self), box);
gtk_box_set_center_widget (GTK_BOX (box), GTK_WIDGET (self->switcher));
gtk_box_pack_end (GTK_BOX (box), self->show_all, TRUE, TRUE, 0);
gtk_widget_set_halign (self->show_all, GTK_ALIGN_END);
self->pan_gesture = gtk_gesture_pan_new (GTK_WIDGET (self->stack), GTK_ORIENTATION_HORIZONTAL);
g_signal_connect (self->pan_gesture, "pan",
G_CALLBACK (gtk_shortcuts_section_pan_gesture_pan), self);
}
static void
gtk_shortcuts_section_set_view_name (GtkShortcutsSection *self,
const gchar *view_name)
{
g_return_if_fail (GTK_IS_SHORTCUTS_SECTION (self));
if (g_strcmp0 (self->view_name, view_name) == 0)
return;
g_free (self->view_name);
self->view_name = g_strdup (view_name);
gtk_shortcuts_section_filter_groups (self);
gtk_shortcuts_section_reflow_groups (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VIEW_NAME]);
}
static void
gtk_shortcuts_section_add_group (GtkShortcutsSection *self,
GtkShortcutsGroup *group)
{
GList *children;
GtkWidget *page, *column;
g_return_if_fail (GTK_IS_SHORTCUTS_SECTION (self));
g_return_if_fail (GTK_IS_SHORTCUTS_GROUP (group));
children = gtk_container_get_children (GTK_CONTAINER (self->stack));
if (children)
page = children->data;
else
{
page = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 22);
gtk_stack_add_named (self->stack, page, "1");
}
g_list_free (children);
children = gtk_container_get_children (GTK_CONTAINER (page));
if (children)
column = children->data;
else
{
column = gtk_box_new (GTK_ORIENTATION_VERTICAL, 22);
gtk_container_add (GTK_CONTAINER (page), column);
}
g_list_free (children);
gtk_container_add (GTK_CONTAINER (column), GTK_WIDGET (group));
gtk_shortcuts_section_maybe_reflow (self);
}
static void
gtk_shortcuts_section_show_all (GtkShortcutsSection *self)
{
gtk_shortcuts_section_set_view_name (self, NULL);
}
static void
update_group_visibility (GtkWidget *child, gpointer data)
{
GtkShortcutsSection *self = data;
if (GTK_IS_SHORTCUTS_GROUP (child))
{
gchar *view;
gboolean match;
g_object_get (child, "view", &view, NULL);
match = view == NULL ||
self->view_name == NULL ||
strcmp (view, self->view_name) == 0;
gtk_widget_set_visible (child, match);
self->has_filtered_group |= !match;
g_free (view);
}
else if (GTK_IS_CONTAINER (child))
{
gtk_container_foreach (GTK_CONTAINER (child), update_group_visibility, data);
}
}
static void
gtk_shortcuts_section_filter_groups (GtkShortcutsSection *self)
{
self->has_filtered_group = FALSE;
gtk_container_foreach (GTK_CONTAINER (self), update_group_visibility, self);
gtk_widget_set_visible (GTK_WIDGET (self->show_all), self->has_filtered_group);
gtk_widget_set_visible (gtk_widget_get_parent (GTK_WIDGET (self->show_all)),
gtk_widget_get_visible (GTK_WIDGET (self->show_all)) ||
gtk_widget_get_visible (GTK_WIDGET (self->switcher)));
}
static void
gtk_shortcuts_section_maybe_reflow (GtkShortcutsSection *self)
{
if (gtk_widget_get_mapped (GTK_WIDGET (self)))
gtk_shortcuts_section_reflow_groups (self);
else
self->need_reflow = TRUE;
}
static void
adjust_page_buttons (GtkWidget *widget,
gpointer data)
{
GtkWidget *label;
/*
* TODO: This is a hack to get the GtkStackSwitcher radio
* buttons to look how we want. However, it's very
* much font size specific.
*/
gtk_widget_set_size_request (widget, 34, 34);
label = gtk_bin_get_child (GTK_BIN (widget));
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
}
static void
gtk_shortcuts_section_reflow_groups (GtkShortcutsSection *self)
{
GList *pages, *p;
GList *columns, *c;
GList *groups, *g;
GList *children;
guint n_rows;
guint n_columns;
guint n_pages;
GtkWidget *current_page, *current_column;
/* collect all groups from the current pages */
groups = NULL;
pages = gtk_container_get_children (GTK_CONTAINER (self->stack));
for (p = pages; p; p = p->next)
{
columns = gtk_container_get_children (GTK_CONTAINER (p->data));
for (c = columns; c; c = c->next)
{
children = gtk_container_get_children (GTK_CONTAINER (c->data));
groups = g_list_concat (groups, children);
}
g_list_free (columns);
}
g_list_free (pages);
/* create new pages */
current_page = NULL;
current_column = NULL;
pages = NULL;
n_rows = 0;
n_columns = 0;
n_pages = 0;
for (g = groups; g; g = g->next)
{
GtkShortcutsGroup *group = g->data;
guint height;
gboolean visible;
g_object_get (group,
"visible", &visible,
"height", &height,
NULL);
if (!visible)
height = 0;
if (n_rows == 0 || n_rows + height > self->max_height)
{
GtkWidget *column;
column = gtk_box_new (GTK_ORIENTATION_VERTICAL, 22);
gtk_widget_show (column);
g_object_set_data_full (G_OBJECT (column), "accel-size-group", gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL), g_object_unref);
g_object_set_data_full (G_OBJECT (column), "title-size-group", gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL), g_object_unref);
if (n_columns % 2 == 0)
{
GtkWidget *page;
page = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 22);
gtk_widget_show (page);
pages = g_list_append (pages, page);
current_page = page;
}
gtk_container_add (GTK_CONTAINER (current_page), column);
current_column = column;
n_columns += 1;
n_rows = 0;
}
n_rows += height;
g_object_set (group,
"accel-size-group", g_object_get_data (G_OBJECT (current_column), "accel-size-group"),
"title-size-group", g_object_get_data (G_OBJECT (current_column), "title-size-group"),
NULL);
g_object_ref (group);
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (GTK_WIDGET (group))), GTK_WIDGET (group));
gtk_container_add (GTK_CONTAINER (current_column), GTK_WIDGET (group));
g_object_unref (group);
}
/* balance the last page */
if (n_columns % 2 == 1)
{
GtkWidget *column;
GList *content;
guint n;
column = gtk_box_new (GTK_ORIENTATION_VERTICAL, 22);
gtk_widget_show (column);
g_object_set_data_full (G_OBJECT (column), "accel-size-group", gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL), g_object_unref);
g_object_set_data_full (G_OBJECT (column), "title-size-group", gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL), g_object_unref);
gtk_container_add (GTK_CONTAINER (current_page), column);
content = gtk_container_get_children (GTK_CONTAINER (current_column));
n = 0;
for (g = g_list_last (content); g; g = g->prev)
{
GtkShortcutsGroup *group = g->data;
guint height;
gboolean visible;
g_object_get (group,
"visible", &visible,
"height", &height,
NULL);
if (!visible)
height = 0;
if (n_rows - height == 0)
break;
if (ABS (n_rows - n) < ABS ((n_rows - height) - (n + height)))
break;
n_rows -= height;
n += height;
}
for (g = g->next; g; g = g->next)
{
GtkShortcutsGroup *group = g->data;
g_object_set (group,
"accel-size-group", g_object_get_data (G_OBJECT (column), "accel-size-group"),
"title-size-group", g_object_get_data (G_OBJECT (column), "title-size-group"),
NULL);
g_object_ref (group);
gtk_container_remove (GTK_CONTAINER (current_column), GTK_WIDGET (group));
gtk_container_add (GTK_CONTAINER (column), GTK_WIDGET (group));
g_object_unref (group);
}
g_list_free (content);
}
/* replace the current pages with the new pages */
children = gtk_container_get_children (GTK_CONTAINER (self->stack));
g_list_free_full (children, (GDestroyNotify)gtk_widget_destroy);
for (p = pages, n_pages = 0; p; p = p->next, n_pages++)
{
GtkWidget *page = p->data;
gchar *title;
title = g_strdup_printf ("_%u", n_pages + 1);
gtk_stack_add_titled (self->stack, page, title, title);
g_free (title);
}
/* fix up stack switcher */
gtk_container_foreach (GTK_CONTAINER (self->switcher), adjust_page_buttons, NULL);
gtk_widget_set_visible (GTK_WIDGET (self->switcher), (n_pages > 1));
gtk_widget_set_visible (gtk_widget_get_parent (GTK_WIDGET (self->switcher)),
gtk_widget_get_visible (GTK_WIDGET (self->show_all)) ||
gtk_widget_get_visible (GTK_WIDGET (self->switcher)));
/* clean up */
g_list_free (groups);
g_list_free (pages);
self->need_reflow = FALSE;
}
static gboolean
gtk_shortcuts_section_change_current_page (GtkShortcutsSection *self,
gint offset)
{
GtkWidget *child;
GList *children, *l;
child = gtk_stack_get_visible_child (self->stack);
children = gtk_container_get_children (GTK_CONTAINER (self->stack));
l = g_list_find (children, child);
if (offset == 1)
l = l->next;
else if (offset == -1)
l = l->prev;
else
g_assert_not_reached ();
if (l)
gtk_stack_set_visible_child (self->stack, GTK_WIDGET (l->data));
else
gtk_widget_error_bell (GTK_WIDGET (self));
g_list_free (children);
return TRUE;
}
static void
gtk_shortcuts_section_pan_gesture_pan (GtkGesturePan *gesture,
GtkPanDirection direction,
gdouble offset,
GtkShortcutsSection *self)
{
if (offset < 50)
return;
if (direction == GTK_PAN_DIRECTION_LEFT)
gtk_shortcuts_section_change_current_page (self, 1);
else if (direction == GTK_PAN_DIRECTION_RIGHT)
gtk_shortcuts_section_change_current_page (self, -1);
else
g_assert_not_reached ();
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
}

43
gtk/gtkshortcutssection.h Normal file
View File

@@ -0,0 +1,43 @@
/* gtkshortcutssection.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_SHORTCUTS_SECTION_H__
#define __GTK_SHORTCUTS_SECTION_H__
#include <gtk/gtkbox.h>
#include <gtk/gtkshortcutsgroup.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHORTCUTS_SECTION (gtk_shortcuts_section_get_type ())
#define GTK_SHORTCUTS_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SHORTCUTS_SECTION, GtkShortcutsSection))
#define GTK_SHORTCUTS_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SHORTCUTS_SECTION, GtkShortcutsSectionClass))
#define GTK_IS_SHORTCUTS_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SHORTCUTS_SECTION))
#define GTK_IS_SHORTCUTS_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SHORTCUTS_SECTION))
#define GTK_SHORTCUTS_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SHORTCUTS_SECTION, GtkShortcutsSectionClass))
typedef struct _GtkShortcutsSection GtkShortcutsSection;
typedef struct _GtkShortcutsSectionClass GtkShortcutsSectionClass;
GDK_AVAILABLE_IN_3_20
GType gtk_shortcuts_section_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GTK_SHORTCUTS_SECTION_H__ */

264
gtk/gtkshortcutsshortcut.c Normal file
View File

@@ -0,0 +1,264 @@
/* gtkshortcutsshortcut.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkshortcutsshortcut.h"
#include "gtkshortcutlabelprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
/**
* SECTION:gtkshortcutsshortcut
* @Title: GtkShortcutsShortcut
* @Short_description: Represents a keyboard shortcut in a GtkShortcutsWindow
*
* A GtkShortcutsShortcut represents a single keyboard shortcut with
* a short text. This widget is only meant to be used with
* #GtkShortcutsWindow.
*/
struct _GtkShortcutsShortcut
{
GtkBox parent_instance;
GtkShortcutLabel *accelerator;
GtkLabel *title;
GtkSizeGroup *accel_size_group;
GtkSizeGroup *title_size_group;
};
struct _GtkShortcutsShortcutClass
{
GtkBoxClass parent_class;
};
G_DEFINE_TYPE (GtkShortcutsShortcut, gtk_shortcuts_shortcut, GTK_TYPE_BOX)
enum {
PROP_0,
PROP_ACCELERATOR,
PROP_TITLE,
PROP_ACCEL_SIZE_GROUP,
PROP_TITLE_SIZE_GROUP,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP];
static void
gtk_shortcuts_shortcut_set_accel_size_group (GtkShortcutsShortcut *self,
GtkSizeGroup *group)
{
if (self->accel_size_group)
gtk_size_group_remove_widget (self->accel_size_group, GTK_WIDGET (self->accelerator));
if (group)
gtk_size_group_add_widget (group, GTK_WIDGET (self->accelerator));
g_set_object (&self->accel_size_group, group);
}
static void
gtk_shortcuts_shortcut_set_title_size_group (GtkShortcutsShortcut *self,
GtkSizeGroup *group)
{
if (self->title_size_group)
gtk_size_group_remove_widget (self->title_size_group, GTK_WIDGET (self->title));
if (group)
gtk_size_group_add_widget (group, GTK_WIDGET (self->title));
g_set_object (&self->title_size_group, group);
}
static void
gtk_shortcuts_shortcut_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkShortcutsShortcut *self = GTK_SHORTCUTS_SHORTCUT (object);
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, gtk_label_get_label (self->title));
break;
case PROP_ACCELERATOR:
g_value_set_string (value, gtk_shortcut_label_get_accelerator (self->accelerator));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_shortcut_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkShortcutsShortcut *self = GTK_SHORTCUTS_SHORTCUT (object);
switch (prop_id)
{
case PROP_ACCELERATOR:
gtk_shortcut_label_set_accelerator (self->accelerator, g_value_get_string (value));
break;
case PROP_ACCEL_SIZE_GROUP:
gtk_shortcuts_shortcut_set_accel_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
break;
case PROP_TITLE:
gtk_label_set_label (self->title, g_value_get_string (value));
break;
case PROP_TITLE_SIZE_GROUP:
gtk_shortcuts_shortcut_set_title_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_shortcuts_shortcut_finalize (GObject *object)
{
GtkShortcutsShortcut *self = GTK_SHORTCUTS_SHORTCUT (object);
g_clear_object (&self->accel_size_group);
g_clear_object (&self->title_size_group);
G_OBJECT_CLASS (gtk_shortcuts_shortcut_parent_class)->finalize (object);
}
static void
gtk_shortcuts_shortcut_add (GtkContainer *container,
GtkWidget *widget)
{
g_warning ("Can't add children to %s", G_OBJECT_TYPE_NAME (container));
}
static GType
gtk_shortcuts_shortcut_child_type (GtkContainer *container)
{
return G_TYPE_NONE;
}
static void
gtk_shortcuts_shortcut_class_init (GtkShortcutsShortcutClass *klass)
{
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_shortcuts_shortcut_finalize;
object_class->get_property = gtk_shortcuts_shortcut_get_property;
object_class->set_property = gtk_shortcuts_shortcut_set_property;
container_class->add = gtk_shortcuts_shortcut_add;
container_class->child_type = gtk_shortcuts_shortcut_child_type;
/**
* GtkShortcutsShortcut:accelerator:
*
* The accelerator(s) represented by this object, in the syntax
* understood by gtk_accelerator_parse(). Multiple accelerators
* can be specified by separating them with a space, but keep in
* mind that the available width is limited.
*
* Here is an example: <ctrl>? F1
*
* Note that < and > need to escaped as &lt; and &gt; when used
* in .ui files.
*/
properties[PROP_ACCELERATOR] =
g_param_spec_string ("accelerator",
P_("Accelerator"),
P_("Accelerator"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsShortcut:title:
*
* The textual description for the accelerators represented by
* this object. This should be a short string that can fit in
* a single line.
*/
properties[PROP_TITLE] =
g_param_spec_string ("title",
P_("Title"),
P_("Title"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsShortcut:accel-size-group:
*
* The size group for the accelerator portion of this shortcut.
*
* This is used internally by GTK+, and must not be modified by applications.
*/
properties[PROP_ACCEL_SIZE_GROUP] =
g_param_spec_object ("accel-size-group",
P_("Accelerator Size Group"),
P_("Accelerator Size Group"),
GTK_TYPE_SIZE_GROUP,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsShortcut:title-size-group:
*
* The size group for the textual portion of this shortcut.
*
* This is used internally by GTK+, and must not be modified by applications.
*/
properties[PROP_TITLE_SIZE_GROUP] =
g_param_spec_object ("title-size-group",
P_("Title Size Group"),
P_("Title Size Group"),
GTK_TYPE_SIZE_GROUP,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
static void
gtk_shortcuts_shortcut_init (GtkShortcutsShortcut *self)
{
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL);
gtk_box_set_spacing (GTK_BOX (self), 12);
self->accelerator = g_object_new (GTK_TYPE_SHORTCUT_LABEL,
"visible", TRUE,
NULL);
GTK_CONTAINER_CLASS (gtk_shortcuts_shortcut_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (self->accelerator));
self->title = g_object_new (GTK_TYPE_LABEL,
"hexpand", TRUE,
"visible", TRUE,
"xalign", 0.0f,
NULL);
GTK_CONTAINER_CLASS (gtk_shortcuts_shortcut_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (self->title));
}

View File

@@ -0,0 +1,43 @@
/* gtkshortcutsshortcutprivate.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GTK_SHORTCUTS_SHORTCUT_H
#define GTK_SHORTCUTS_SHORTCUT_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHORTCUTS_SHORTCUT (gtk_shortcuts_shortcut_get_type())
#define GTK_SHORTCUTS_SHORTCUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SHORTCUTS_SHORTCUT, GtkShortcutsShortcut))
#define GTK_SHORTCUTS_SHORTCUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SHORTCUTS_SHORTCUT, GtkShortcutsShortcutClass))
#define GTK_IS_SHORTCUTS_SHORTCUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SHORTCUTS_SHORTCUT))
#define GTK_IS_SHORTCUTS_SHORTCUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SHORTCUTS_SHORTCUT))
#define GTK_SHORTCUTS_SHORTCUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SHORTCUTS_SHORTCUT, GtkShortcutsShortcutClass))
typedef struct _GtkShortcutsShortcut GtkShortcutsShortcut;
typedef struct _GtkShortcutsShortcutClass GtkShortcutsShortcutClass;
GDK_AVAILABLE_IN_3_20
GType gtk_shortcuts_shortcut_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* GTK_SHORTCUTS_SHORTCUT_H */

882
gtk/gtkshortcutswindow.c Normal file
View File

@@ -0,0 +1,882 @@
/* gtkshortcutswindow.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkshortcutswindow.h"
#include "gtkscrolledwindow.h"
#include "gtkshortcutssection.h"
#include "gtkshortcutsgroup.h"
#include "gtkshortcutsgesture.h"
#include "gtkshortcutsshortcut.h"
#include "gtksearchbar.h"
#include "gtksearchentry.h"
#include "gtkprivate.h"
#include "gtkintl.h"
/**
* SECTION:gtkshortcutswindow
* @Title: GtkShortcutsWindow
* @Short_description: Toplevel which shows help for shortcuts
*
* A GtkShortcutsWindow shows brief information about the keyboard shortcuts
* and gestures of an application. The shortcuts can be grouped, and you can
* have multiple sections in this window, corresponding to the major modes of
* your application.
*
* Additionally, the shortcuts can be filtered by the current view, to avoid
* showing information that is not relevant in the current application context.
*
* The recommended way to construct a GtkShortcutsWindow is with GtkBuilder,
* by populating a #GtkShortcutsWindow with one or more #GtkShortcutsSection
* objects, which contain #GtkShortcutsGroups that in turn contain objects of
* class #GtkShortcutsShortcut or #GtkShortcutsGesture.
*
* # A simple example:
*
* ![](gedit-shortcuts.png)
*
* This example has as single section. As you can see, the shortcut groups
* are arranged in columns, and spread across several pages if there are too
* many to find on a single page.
*
* The .ui file for this example can be found [here](https://git.gnome.org/browse/gtk+/tree/demos/gtk-demo/shortcuts-gedit.ui).
*
* # An example with multiple views:
*
* ![](clocks-shortcuts.png)
*
* This example shows a #GtkShortcutsWindow that has been configured to show only
* the shortcuts relevant to the "stopwatch" view.
*
* The .ui file for this example can be found [here](https://git.gnome.org/browse/gtk+/tree/demos/gtk-demo/shortcuts-clocks.ui).
*
* # An example with multiple sections:
*
* ![](builder-shortcuts.png)
*
* This example shows a #GtkShortcutsWindow with two sections, "Editor Shortcuts"
* and "Terminal Shortcuts".
*
* The .ui file for this example can be found [here](https://git.gnome.org/browse/gtk+/tree/demos/gtk-demo/shortcuts-clocks.ui).
*/
typedef struct
{
GHashTable *keywords;
gchar *initial_section;
gchar *last_section_name;
gchar *view_name;
GtkSizeGroup *search_text_group;
GtkSizeGroup *search_image_group;
GHashTable *search_items_hash;
GtkStack *stack;
GtkStack *title_stack;
GtkMenuButton *menu_button;
GtkLabel *menu_label;
GtkSearchBar *search_bar;
GtkSearchEntry *search_entry;
GtkHeaderBar *header_bar;
GtkPopover *popover;
GtkListBox *list_box;
GtkBox *search_gestures;
GtkBox *search_shortcuts;
} GtkShortcutsWindowPrivate;
typedef struct
{
GtkShortcutsWindow *self;
GtkBuilder *builder;
GQueue *stack;
gchar *property_name;
guint translatable : 1;
} ViewsParserData;
G_DEFINE_TYPE_WITH_PRIVATE (GtkShortcutsWindow, gtk_shortcuts_window, GTK_TYPE_WINDOW)
enum {
CLOSE,
SEARCH,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_SECTION_NAME,
PROP_VIEW_NAME,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP];
static guint signals[LAST_SIGNAL];
static gint
number_of_children (GtkContainer *container)
{
GList *children;
gint n;
children = gtk_container_get_children (container);
n = g_list_length (children);
g_list_free (children);
return n;
}
static void
update_title_stack (GtkShortcutsWindow *self)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
GtkWidget *visible_child;
visible_child = gtk_stack_get_visible_child (priv->stack);
if (GTK_IS_SHORTCUTS_SECTION (visible_child))
{
if (number_of_children (GTK_CONTAINER (priv->stack)) > 3)
{
gchar *title;
gtk_stack_set_visible_child_name (priv->title_stack, "sections");
g_object_get (visible_child, "title", &title, NULL);
gtk_label_set_label (priv->menu_label, title);
g_free (title);
}
else
{
gtk_stack_set_visible_child_name (priv->title_stack, "title");
}
}
else if (visible_child != NULL)
{
gtk_stack_set_visible_child_name (priv->title_stack, "search");
}
}
static void
gtk_shortcuts_window_add_search_item (GtkWidget *child, gpointer data)
{
GtkShortcutsWindow *self = data;
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
GtkWidget *item;
gchar *subtitle = NULL;
gchar *accelerator = NULL;
gchar *title = NULL;
gchar *hash_key = NULL;
GIcon *icon = NULL;
gchar *str;
gchar *keywords;
if (GTK_IS_SHORTCUTS_SHORTCUT (child))
{
g_object_get (child,
"accelerator", &accelerator,
"title", &title,
NULL);
hash_key = g_strdup_printf ("%s-%s", title, accelerator);
if (g_hash_table_contains (priv->search_items_hash, hash_key))
{
g_free (hash_key);
g_free (title);
g_free (accelerator);
return;
}
g_hash_table_insert (priv->search_items_hash, hash_key, GINT_TO_POINTER (1));
item = g_object_new (GTK_TYPE_SHORTCUTS_SHORTCUT,
"visible", TRUE,
"accelerator", accelerator,
"title", title,
"accel-size-group", priv->search_image_group,
"title-size-group", priv->search_text_group,
NULL);
str = g_strdup_printf ("%s %s", accelerator, title);
keywords = g_utf8_strdown (str, -1);
g_hash_table_insert (priv->keywords, item, keywords);
gtk_container_add (GTK_CONTAINER (priv->search_shortcuts), item);
g_free (title);
g_free (accelerator);
g_free (str);
}
else if (GTK_IS_SHORTCUTS_GESTURE (child))
{
g_object_get (child,
"title", &title,
"subtitle", &subtitle,
"icon", &icon,
NULL);
hash_key = g_strdup_printf ("%s-%s", title, subtitle);
if (g_hash_table_contains (priv->search_items_hash, hash_key))
{
g_free (subtitle);
g_free (title);
g_free (hash_key);
g_clear_object (&icon);
return;
}
g_hash_table_insert (priv->search_items_hash, hash_key, GINT_TO_POINTER (1));
item = g_object_new (GTK_TYPE_SHORTCUTS_GESTURE,
"visible", TRUE,
"title", title,
"subtitle", subtitle,
"icon", icon,
"icon-size-group", priv->search_image_group,
"title-size-group", priv->search_text_group,
NULL);
str = g_strdup_printf ("%s %s", title, subtitle);
keywords = g_utf8_strdown (str, -1);
g_hash_table_insert (priv->keywords, item, keywords);
gtk_container_add (GTK_CONTAINER (priv->search_gestures), item);
g_free (subtitle);
g_free (title);
g_clear_object (&icon);
g_free (str);
}
else if (GTK_IS_CONTAINER (child))
{
gtk_container_foreach (GTK_CONTAINER (child), gtk_shortcuts_window_add_search_item, self);
}
}
static void
gtk_shortcuts_window_add_section (GtkShortcutsWindow *self,
GtkShortcutsSection *section)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
GtkListBoxRow *row;
gchar *title;
gchar *name;
const gchar *visible_section;
GtkWidget *label;
gtk_container_foreach (GTK_CONTAINER (section), gtk_shortcuts_window_add_search_item, self);
g_object_get (section,
"section-name", &name,
"title", &title,
NULL);
if (name == NULL)
name = g_strdup ("shortcuts");
gtk_stack_add_titled (priv->stack, GTK_WIDGET (section), name, title);
visible_section = gtk_stack_get_visible_child_name (priv->stack);
if (strcmp (visible_section, "internal-search") == 0 ||
(priv->initial_section && strcmp (priv->initial_section, visible_section) == 0))
gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (section));
row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
"visible", TRUE,
NULL);
g_object_set_data_full (G_OBJECT (row), "GTK_SHORTCUTS_SECTION_NAME", g_strdup (name), g_free);
label = g_object_new (GTK_TYPE_LABEL,
"margin", 6,
"label", title,
"xalign", 0.5f,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (label));
gtk_container_add (GTK_CONTAINER (priv->list_box), GTK_WIDGET (row));
update_title_stack (self);
g_free (name);
g_free (title);
}
static void
gtk_shortcuts_window_add (GtkContainer *container,
GtkWidget *widget)
{
GtkShortcutsWindow *self = (GtkShortcutsWindow *)container;
if (GTK_IS_SHORTCUTS_SECTION (widget))
gtk_shortcuts_window_add_section (self, GTK_SHORTCUTS_SECTION (widget));
else
g_warning ("Can't add children of type %s to %s",
G_OBJECT_TYPE_NAME (widget),
G_OBJECT_TYPE_NAME (container));
}
static void
gtk_shortcuts_window_set_view_name (GtkShortcutsWindow *self,
const gchar *view_name)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
GList *sections, *l;
g_free (priv->view_name);
priv->view_name = g_strdup (view_name);
sections = gtk_container_get_children (GTK_CONTAINER (priv->stack));
for (l = sections; l; l = l->next)
{
GtkShortcutsSection *section = l->data;
if (GTK_IS_SHORTCUTS_SECTION (section))
g_object_set (section, "view-name", priv->view_name, NULL);
}
g_list_free (sections);
}
static void
gtk_shortcuts_window_set_section_name (GtkShortcutsWindow *self,
const gchar *section_name)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
GtkWidget *section;
g_free (priv->initial_section);
priv->initial_section = g_strdup (section_name);
section = gtk_stack_get_child_by_name (priv->stack, section_name);
if (section)
gtk_stack_set_visible_child (priv->stack, section);
}
static void
gtk_shortcuts_window__list_box__row_activated (GtkShortcutsWindow *self,
GtkListBoxRow *row,
GtkListBox *list_box)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
const gchar *name;
name = g_object_get_data (G_OBJECT (row), "GTK_SHORTCUTS_SECTION_NAME");
gtk_stack_set_visible_child_name (priv->stack, name);
gtk_widget_hide (GTK_WIDGET (priv->popover));
}
static void
gtk_shortcuts_window__entry__changed (GtkShortcutsWindow *self,
GtkSearchEntry *search_entry)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
gchar *downcase = NULL;
GHashTableIter iter;
const gchar *text;
const gchar *last_section_name;
gpointer key;
gpointer value;
gboolean has_result;
text = gtk_entry_get_text (GTK_ENTRY (search_entry));
if (!text || !*text)
{
if (priv->last_section_name != NULL)
{
gtk_stack_set_visible_child_name (priv->stack, priv->last_section_name);
return;
}
}
last_section_name = gtk_stack_get_visible_child_name (priv->stack);
if (g_strcmp0 (last_section_name, "internal-search") != 0 &&
g_strcmp0 (last_section_name, "no-search-results") != 0)
{
g_free (priv->last_section_name);
priv->last_section_name = g_strdup (last_section_name);
}
downcase = g_utf8_strdown (text, -1);
g_hash_table_iter_init (&iter, priv->keywords);
has_result = FALSE;
while (g_hash_table_iter_next (&iter, &key, &value))
{
GtkWidget *widget = key;
const gchar *keywords = value;
gboolean match;
match = strstr (keywords, downcase) != NULL;
gtk_widget_set_visible (widget, match);
has_result |= match;
}
g_free (downcase);
if (has_result)
gtk_stack_set_visible_child_name (priv->stack, "internal-search");
else
gtk_stack_set_visible_child_name (priv->stack, "no-search-results");
}
static void
gtk_shortcuts_window__search_mode__changed (GtkShortcutsWindow *self)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
if (!gtk_search_bar_get_search_mode (priv->search_bar))
{
if (priv->last_section_name != NULL)
gtk_stack_set_visible_child_name (priv->stack, priv->last_section_name);
}
}
static void
gtk_shortcuts_window_close (GtkShortcutsWindow *self)
{
gtk_window_close (GTK_WINDOW (self));
}
static void
gtk_shortcuts_window_search (GtkShortcutsWindow *self)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
gtk_search_bar_set_search_mode (priv->search_bar, TRUE);
}
static void
gtk_shortcuts_window_constructed (GObject *object)
{
GtkShortcutsWindow *self = (GtkShortcutsWindow *)object;
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
G_OBJECT_CLASS (gtk_shortcuts_window_parent_class)->constructed (object);
if (priv->initial_section != NULL)
gtk_stack_set_visible_child_name (priv->stack, priv->initial_section);
}
static void
gtk_shortcuts_window_finalize (GObject *object)
{
GtkShortcutsWindow *self = (GtkShortcutsWindow *)object;
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
g_clear_pointer (&priv->keywords, g_hash_table_unref);
g_clear_pointer (&priv->initial_section, g_free);
g_clear_pointer (&priv->view_name, g_free);
g_clear_pointer (&priv->last_section_name, g_free);
g_clear_pointer (&priv->search_items_hash, g_hash_table_unref);
g_clear_object (&priv->search_image_group);
g_clear_object (&priv->search_text_group);
G_OBJECT_CLASS (gtk_shortcuts_window_parent_class)->finalize (object);
}
static void
gtk_shortcuts_window_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkShortcutsWindow *self = (GtkShortcutsWindow *)object;
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
switch (prop_id)
{
case PROP_SECTION_NAME:
{
GtkWidget *child = gtk_stack_get_visible_child (priv->stack);
if (child != NULL)
{
gchar *name = NULL;
gtk_container_child_get (GTK_CONTAINER (priv->stack), child,
"name", &name,
NULL);
g_value_take_string (value, name);
}
}
break;
case PROP_VIEW_NAME:
g_value_set_string (value, priv->view_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_window_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkShortcutsWindow *self = (GtkShortcutsWindow *)object;
switch (prop_id)
{
case PROP_SECTION_NAME:
gtk_shortcuts_window_set_section_name (self, g_value_get_string (value));
break;
case PROP_VIEW_NAME:
gtk_shortcuts_window_set_view_name (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_shortcuts_window_unmap (GtkWidget *widget)
{
GtkShortcutsWindow *self = (GtkShortcutsWindow *)widget;
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
gtk_search_bar_set_search_mode (priv->search_bar, FALSE);
GTK_WIDGET_CLASS (gtk_shortcuts_window_parent_class)->unmap (widget);
}
static GType
gtk_shortcuts_window_child_type (GtkContainer *container)
{
return GTK_TYPE_SHORTCUTS_SECTION;
}
static void
gtk_shortcuts_window_class_init (GtkShortcutsWindowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
GtkBindingSet *binding_set = gtk_binding_set_by_class (klass);
object_class->constructed = gtk_shortcuts_window_constructed;
object_class->finalize = gtk_shortcuts_window_finalize;
object_class->get_property = gtk_shortcuts_window_get_property;
object_class->set_property = gtk_shortcuts_window_set_property;
widget_class->unmap = gtk_shortcuts_window_unmap;
container_class->add = gtk_shortcuts_window_add;
container_class->child_type = gtk_shortcuts_window_child_type;
klass->close = gtk_shortcuts_window_close;
klass->search = gtk_shortcuts_window_search;
/**
* GtkShortcutsWindow:section-name:
*
* The name of the section to show.
*
* This should be the section-name of one of the #GtkShortcutsSection
* objects that are in this shortcuts window.
*/
properties[PROP_SECTION_NAME] =
g_param_spec_string ("section-name", P_("Section Name"), P_("Section Name"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GtkShortcutsWindow:view-name:
*
* The view name by which to filter the contents.
*
* This should correspond to the #GtkShortcutsGroup:view property of some of
* the #GtkShortcutsGroup objects that are inside this shortcuts window.
*
* Set this to %NULL to show all groups.
*/
properties[PROP_VIEW_NAME] =
g_param_spec_string ("view-name", P_("View Name"), P_("View Name"),
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
/**
* GtkShortcutsWindow::close:
*
* The ::close signal is a
* [keybinding signal][GtkBindingSignal]
* which gets emitted when the user uses a keybinding to close
* the window.
*
* The default binding for this signal is the Escape key.
*/
signals[CLOSE] = g_signal_new (I_("close"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkShortcutsWindowClass, close),
NULL, NULL, NULL,
G_TYPE_NONE,
0);
/**
* GtkShortcutsWindow::search:
*
* The ::search signal is a
* [keybinding signal][GtkBindingSignal]
* which gets emitted when the user uses a keybinding to start a search.
*
* The default binding for this signal is Control-F.
*/
signals[SEARCH] = g_signal_new (I_("search"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkShortcutsWindowClass, search),
NULL, NULL, NULL,
G_TYPE_NONE,
0);
gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "search", 0);
g_type_ensure (GTK_TYPE_SHORTCUTS_GROUP);
g_type_ensure (GTK_TYPE_SHORTCUTS_GROUP);
g_type_ensure (GTK_TYPE_SHORTCUTS_GESTURE);
g_type_ensure (GTK_TYPE_SHORTCUTS_SHORTCUT);
}
static gboolean
window_key_press_event_cb (GtkWidget *window,
GdkEvent *event,
gpointer data)
{
GtkShortcutsWindow *self = GTK_SHORTCUTS_WINDOW (window);
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
return gtk_search_bar_handle_event (priv->search_bar, event);
}
static void
gtk_shortcuts_window_init (GtkShortcutsWindow *self)
{
GtkShortcutsWindowPrivate *priv = gtk_shortcuts_window_get_instance_private (self);
GtkToggleButton *search_button;
GtkBox *main_box;
GtkBox *menu_box;
GtkBox *box;
GtkArrow *arrow;
GtkWidget *scroller;
GtkWidget *label;
GtkWidget *empty;
PangoAttrList *attributes;
gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
gtk_window_set_type_hint (GTK_WINDOW (self), GDK_WINDOW_TYPE_HINT_DIALOG);
g_signal_connect (self, "key-press-event",
G_CALLBACK (window_key_press_event_cb), NULL);
priv->keywords = g_hash_table_new_full (NULL, NULL, NULL, g_free);
priv->search_items_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
priv->search_text_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->search_image_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->header_bar = g_object_new (GTK_TYPE_HEADER_BAR,
"show-close-button", TRUE,
"visible", TRUE,
NULL);
gtk_window_set_titlebar (GTK_WINDOW (self), GTK_WIDGET (priv->header_bar));
search_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
"child", g_object_new (GTK_TYPE_IMAGE,
"visible", TRUE,
"icon-name", "edit-find-symbolic",
NULL),
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (priv->header_bar), GTK_WIDGET (search_button));
main_box = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
GTK_CONTAINER_CLASS (gtk_shortcuts_window_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (main_box));
priv->search_bar = g_object_new (GTK_TYPE_SEARCH_BAR,
"visible", TRUE,
NULL);
g_object_bind_property (priv->search_bar, "search-mode-enabled",
search_button, "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
gtk_container_add (GTK_CONTAINER (main_box), GTK_WIDGET (priv->search_bar));
priv->stack = g_object_new (GTK_TYPE_STACK,
"expand", TRUE,
"homogeneous", TRUE,
"transition-type", GTK_STACK_TRANSITION_TYPE_CROSSFADE,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (main_box), GTK_WIDGET (priv->stack));
priv->title_stack = g_object_new (GTK_TYPE_STACK,
"visible", TRUE,
NULL);
gtk_header_bar_set_custom_title (priv->header_bar, GTK_WIDGET (priv->title_stack));
label = gtk_label_new (_("Shortcuts"));
gtk_widget_show (label);
gtk_style_context_add_class (gtk_widget_get_style_context (label), "title");
gtk_stack_add_named (priv->title_stack, label, "title");
label = gtk_label_new (_("Search Results"));
gtk_widget_show (label);
gtk_style_context_add_class (gtk_widget_get_style_context (label), "title");
gtk_stack_add_named (priv->title_stack, label, "search");
priv->menu_button = g_object_new (GTK_TYPE_MENU_BUTTON,
"focus-on-click", FALSE,
"visible", TRUE,
NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (priv->menu_button)), "flat");
gtk_stack_add_named (priv->title_stack, GTK_WIDGET (priv->menu_button), "sections");
menu_box = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"spacing", 6,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (priv->menu_button), GTK_WIDGET (menu_box));
priv->menu_label = g_object_new (GTK_TYPE_LABEL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (menu_box), GTK_WIDGET (priv->menu_label));
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
arrow = g_object_new (GTK_TYPE_ARROW,
"arrow-type", GTK_ARROW_DOWN,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (menu_box), GTK_WIDGET (arrow));
G_GNUC_END_IGNORE_DEPRECATIONS;
priv->popover = g_object_new (GTK_TYPE_POPOVER,
"border-width", 6,
"relative-to", priv->menu_button,
"position", GTK_POS_BOTTOM,
NULL);
gtk_menu_button_set_popover (priv->menu_button, GTK_WIDGET (priv->popover));
priv->list_box = g_object_new (GTK_TYPE_LIST_BOX,
"selection-mode", GTK_SELECTION_NONE,
"visible", TRUE,
NULL);
g_signal_connect_object (priv->list_box,
"row-activated",
G_CALLBACK (gtk_shortcuts_window__list_box__row_activated),
self,
G_CONNECT_SWAPPED);
gtk_container_add (GTK_CONTAINER (priv->popover), GTK_WIDGET (priv->list_box));
priv->search_entry = GTK_SEARCH_ENTRY (gtk_search_entry_new ());
gtk_widget_show (GTK_WIDGET (priv->search_entry));
gtk_container_add (GTK_CONTAINER (priv->search_bar), GTK_WIDGET (priv->search_entry));
g_object_set (priv->search_entry,
"placeholder-text", _("Search Shortcuts"),
"width-chars", 40,
NULL);
g_signal_connect_object (priv->search_entry,
"search-changed",
G_CALLBACK (gtk_shortcuts_window__entry__changed),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->search_bar,
"notify::search-mode-enabled",
G_CALLBACK (gtk_shortcuts_window__search_mode__changed),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->stack, "notify::visible-child",
G_CALLBACK (update_title_stack), self, G_CONNECT_SWAPPED);
scroller = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"visible", TRUE,
NULL);
box = g_object_new (GTK_TYPE_BOX,
"border-width", 24,
"halign", GTK_ALIGN_CENTER,
"spacing", 24,
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (box));
gtk_stack_add_named (priv->stack, scroller, "internal-search");
priv->search_shortcuts = g_object_new (GTK_TYPE_BOX,
"halign", GTK_ALIGN_CENTER,
"spacing", 6,
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (priv->search_shortcuts));
priv->search_gestures = g_object_new (GTK_TYPE_BOX,
"halign", GTK_ALIGN_CENTER,
"spacing", 6,
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (priv->search_gestures));
empty = g_object_new (GTK_TYPE_GRID,
"visible", TRUE,
"row-spacing", 12,
"margin", 12,
"hexpand", TRUE,
"vexpand", TRUE,
"halign", GTK_ALIGN_CENTER,
"valign", GTK_ALIGN_CENTER,
NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (empty), "dim-label");
gtk_grid_attach (GTK_GRID (empty),
g_object_new (GTK_TYPE_IMAGE,
"visible", TRUE,
"icon-name", "edit-find-symbolic",
"pixel-size", 72,
NULL),
0, 0, 1, 1);
attributes = pango_attr_list_new ();
pango_attr_list_insert (attributes, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
pango_attr_list_insert (attributes, pango_attr_scale_new (1.44));
label = g_object_new (GTK_TYPE_LABEL,
"visible", TRUE,
"label", _("No Results Found"),
"attributes", attributes,
NULL);
pango_attr_list_unref (attributes);
gtk_grid_attach (GTK_GRID (empty), label, 0, 1, 1, 1);
label = g_object_new (GTK_TYPE_LABEL,
"visible", TRUE,
"label", _("Try a different search"),
NULL);
gtk_grid_attach (GTK_GRID (empty), label, 0, 2, 1, 1);
gtk_stack_add_named (priv->stack, empty, "no-search-results");
}

57
gtk/gtkshortcutswindow.h Normal file
View File

@@ -0,0 +1,57 @@
/* gtkshortcutswindow.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_SHORTCUTS_WINDOW_H__
#define __GTK_SHORTCUTS_WINDOW_H__
#include <gtk/gtkwindow.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHORTCUTS_WINDOW (gtk_shortcuts_window_get_type ())
#define GTK_SHORTCUTS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SHORTCUTS_WINDOW, GtkShortcutsWindow))
#define GTK_SHORTCUTS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SHORTCUTS_WINDOW, GtkShortcutsWindowClass))
#define GTK_IS_SHORTCUTS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SHORTCUTS_WINDOW))
#define GTK_IS_SHORTCUTS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SHORTCUTS_WINDOW))
#define GTK_SHORTCUTS_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SHORTCUTS_WINDOW, GtkShortcutsWindowClass))
typedef struct _GtkShortcutsWindow GtkShortcutsWindow;
typedef struct _GtkShortcutsWindowClass GtkShortcutsWindowClass;
struct _GtkShortcutsWindow
{
GtkWindow window;
};
struct _GtkShortcutsWindowClass
{
GtkWindowClass parent_class;
void (*close) (GtkShortcutsWindow *self);
void (*search) (GtkShortcutsWindow *self);
};
GDK_AVAILABLE_IN_3_20
GType gtk_shortcuts_window_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* GTK_SHORTCUTS_WINDOW _H */

View File

@@ -3416,3 +3416,23 @@ GtkVolumeButton.button {
@include undershoot(right);
}
}
GtkShortcutsWindow .round .button {
border-radius: 20px;
outline-radius: 20px;
}
GtkShortcutsWindow .round .button .label {
padding: 0;
}
GtkShortcutsWindow GtkShortcutLabel .frame {
background-color: #fefefe;
border: 1px solid #cecece;
border-radius: 5px;
box-shadow: 0px 1px 0px #fff inset,
0px -2px 0px #dedede inset;
color: #555753;
padding: 3px 8px 3px 8px;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff