Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Screenshot popup alert #675

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions extensions/deviceicon/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

from jarabe.frame.frameinvoker import FrameWidgetInvoker
from jarabe.model import brightness
from jarabe.model.screenshot import take_screenshot
from jarabe.gui import ScreenshotPanel
from jarabe import frame


Expand Down Expand Up @@ -92,7 +92,7 @@ def __init__(self, text, icon_name):
icon = Icon(pixel_size=style.SMALL_ICON_SIZE)
icon.props.icon_name = icon_name
icon.props.xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
style.COLOR_BUTTON_GREY.get_svg()))
style.COLOR_BUTTON_GREY.get_svg()))
icon.show()

label = Gtk.Label(text)
Expand Down Expand Up @@ -230,7 +230,7 @@ def __screenshot_cb(self, palette):
def __take_screenshot_cb(self, frame_):
if frame_.is_visible():
return True
take_screenshot()
panel = ScreenshotPanel()
frame_.show()
return False

Expand Down
4 changes: 2 additions & 2 deletions extensions/globalkey/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

from jarabe.model.screenshot import take_screenshot
from jarabe.gui import ScreenshotPanel

BOUND_KEYS = ['<alt>1', 'Print']


def handle_key_press(key):
take_screenshot()
panel = ScreenshotPanel()
3 changes: 2 additions & 1 deletion src/jarabe/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ sugar_PYTHON = \
__init__.py \
main.py \
apisocket.py \
testrunner.py
testrunner.py \
gui.py

nodist_sugar_PYTHON = config.py

338 changes: 338 additions & 0 deletions src/jarabe/gui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,338 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 Utkarsh Tiwari
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Contact information:
# Utkarsh Tiwari [email protected]

import os
import dbus
import cairo
import logging
import StringIO
import tempfile
from gettext import gettext as _

from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import Gio

from sugar3 import env

from sugar3.datastore import datastore
from sugar3.graphics.icon import Icon
from sugar3.graphics import style
from sugar3.graphics.alert import Alert, TimeoutAlert
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports. Can you just run flake8 again?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

from sugar3.graphics import iconentry
from sugar3.graphics.popwindow import PopWindow
from sugar3.graphics.toolbutton import ToolButton


from jarabe.model.session import get_session_manager
from jarabe import config
from jarabe.model import shell


_logger = logging.getLogger('ScreenshotPanel')

THUMBNAIL_SIZE = style.zoom(
Gdk.Screen.height() / 3), style.zoom(Gdk.Screen.height() / 4.5)


class ScreenshotPanel(PopWindow):
'''
Generates a pop papel to allow user to save the
screenshot by the name of his choice
'''

__gtype_name__ = 'ScreenshotPanel'

def __init__(self):
PopWindow.__init__(self)

self._set_screensize()
# self.props.size = ((height / 6),
# (width / 5))
self.get_title_box().props.title = _('Save Screenshot')
self._title_box.close_button.connect('clicked', self._close_cb)
self.set_keep_above(True)

self.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())
self.set_border_width(style.LINE_WIDTH)
self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
self.set_decorated(False)
self.set_resizable(False)

self.connect('key-press-event', self.__key_press_event_cb)

self._toolbar = None
self._canvas = None
self._table = None
self._scrolledwindow = None
self._separator = None
self._section_view = None
self._section_toolbar = None
self._main_toolbar = None

self._hbox = Gtk.HBox()
self._vbox.pack_start(self._hbox, True, True, 0)
self._hbox.show()

self._main_view = Gtk.EventBox()
self._hbox.pack_start(self._main_view, True, True, 0)
self._main_view.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())
self._main_view.show()

self.add(self._vbox)
self._vbox.show()
self._show_main_view()

# Generates the thumbnail
self.screenshot_surface, self.file_path = take_screenshot()
preview_image, activity_title = generate_thumbnail(
self.screenshot_surface)
self._main_view.add(preview_image)
preview_image.show()

self._vbox = Gtk.VBox()
self._hbox.pack_start(self._vbox, True, True, 0)
self._vbox.show()

self._hbox = Gtk.HBox()
self._hbox.show()

# Name entry box
self._name_view = Gtk.EventBox()
self._name_view.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())
self._name_view.show()

# Entry box
self._search_entry = Gtk.Entry()
halign = Gtk.Alignment.new(0, 1, 0, 0)
halign.add(self._name_view)
halign.show()

self._hbox.pack_start(halign, True, True, 0)
self._name_view.add(self._search_entry)
self._search_entry.show()
self._search_entry.set_text(_(activity_title))

self._vbox.pack_start(self._hbox, True, True, 0)

self._buttons_box = Gtk.HButtonBox()
self._buttons_box.set_layout(Gtk.ButtonBoxStyle.CENTER)
self._buttons_box.set_spacing(style.DEFAULT_SPACING)

_ok = Gtk.Button()
_ok.set_image(Icon(icon_name='dialog-ok'))
_ok.set_label(_('Yes'))
_ok.connect('clicked', self.__ok_clicked_cb)
self._buttons_box.pack_start(_ok, True, True, 0)
_ok.show()

_cancel = Gtk.Button()
_cancel.set_image(Icon(icon_name='dialog-cancel'))
_cancel.set_label(_('No'))
_cancel.connect('clicked', self.__cancel_clicked_cb)
self._buttons_box.pack_start(_cancel, True, True, 0)
_cancel.show()

self._vbox.pack_start(self._buttons_box, True, True, 0)
self._buttons_box.show()
self._search_entry.grab_focus()
self.show()

def _close_cb(self):
self.destroy()

def __cancel_clicked_cb(self, widget):
self.destroy()

def __ok_clicked_cb(self, widget):
self.save_screenshot(self._search_entry.get_text())
self.destroy()

def _set_cursor(self, cursor):
self.get_window().set_cursor(cursor)
Gdk.flush()

def _set_screensize(self):
'''
Sets the size of the popup based on
the screen resolution.
'''
width = Gdk.Screen.width() / 4
height = Gdk.Screen.height() / 5
self.set_size_request(width, height)

def _show_main_view(self):
self._main_view.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_BLACK.get_gdk_color())

def __key_press_event_cb(self, window, event):
# if the user clicked out of the window - fix SL #3188
keyname = Gdk.keyval_name(event.keyval)
if keyname == 'Escape':
self.destroy()

if keyname == 'Return':
self.save_screenshot(self._search_entry.get_text())
self.destroy()

if not self.is_active():
self.present()
return False

def save_screenshot(self, title):
settings = Gio.Settings('org.sugarlabs.user')
color = settings.get_string('color')

jobject = datastore.create()
try:
jobject.metadata['title'] = title
jobject.metadata['keep'] = '0'
jobject.metadata['buddies'] = ''
jobject.metadata['preview'] = _get_preview_data(
self.screenshot_surface)
jobject.metadata['icon-color'] = color
jobject.metadata['mime_type'] = 'image/png'
jobject.file_path = self.file_path
datastore.write(jobject, transfer_ownership=True)
finally:
jobject.destroy()
del jobject


def generate_thumbnail(screenshot_surface):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is coppied from somewhere right (which is fine)?

If so, can you delete it in the other place? I don't want to have 2 identical generate_thumbnail functions lying around the codebase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This function is a modified version of the original generate_thumbnail() so the code is unique in itself.

'''
Generates the thumbnail to be displayed
on the screenshot alert popup
'''

window = Gdk.get_default_root_window()
width, height = window.get_width(), window.get_height()
thumb_width, thumb_height = THUMBNAIL_SIZE

cairo_context = cairo.Context(screenshot_surface)
thumb_scale_w = thumb_width * 1.0 / width
thumb_scale_h = thumb_height * 1.0 / height
cairo_context.scale(thumb_scale_w, thumb_scale_h)
Gdk.cairo_set_source_window(cairo_context, window, 0, 0)
cairo_context.paint()

link_width, link_height = THUMBNAIL_SIZE
link_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
link_width, link_height)

cairo_context = cairo.Context(link_surface)
dest_x = style.zoom(0)
dest_y = style.zoom(0)
cairo_context.set_source_surface(screenshot_surface, dest_x, dest_y)
thumb_width, thumb_height = THUMBNAIL_SIZE
cairo_context.rectangle(dest_x, dest_y, thumb_width, thumb_height)
cairo_context.fill()

bg_width, bg_height = THUMBNAIL_SIZE
pixbuf_bg = Gdk.pixbuf_get_from_surface(link_surface, 0, 0,
bg_width, bg_height)

preview_image = Gtk.Image()
preview_image.set_from_pixbuf(pixbuf_bg)

# Set's the default title
content_title = None
shell_model = shell.get_model()
zoom_level = shell_model.zoom_level

# TRANS: Nouns of what a screenshot contains
if zoom_level == shell_model.ZOOM_MESH:
content_title = _('Mesh')
elif zoom_level == shell_model.ZOOM_GROUP:
content_title = _('Group')
elif zoom_level == shell_model.ZOOM_HOME:
content_title = _('Home')
elif zoom_level == shell_model.ZOOM_ACTIVITY:
activity = shell_model.get_active_activity()
if activity is not None:
content_title = activity.get_title()
if content_title is None:
content_title = _('Activity')

if content_title is None:
title = _('Screenshot')
else:
title = _('Screenshot of \"%s\"') % content_title

return preview_image, title


def take_screenshot():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as for the generate_thumbnail function.

'''
Captures a screenshot and saves
it to a temp dir.
'''
tmp_dir = os.path.join(env.get_profile_path(), 'data')
fd, file_path = tempfile.mkstemp(dir=tmp_dir)
os.close(fd)

window = Gdk.get_default_root_window()
width, height = window.get_width(), window.get_height()

screenshot_surface = Gdk.Window.create_similar_surface(
window, cairo.CONTENT_COLOR, width, height)

cr = cairo.Context(screenshot_surface)
Gdk.cairo_set_source_window(cr, window, 0, 0)
cr.paint()
screenshot_surface.write_to_png(file_path)

return screenshot_surface, file_path


def _get_preview_data(screenshot_surface):
screenshot_width = screenshot_surface.get_width()
screenshot_height = screenshot_surface.get_height()

preview_width, preview_height = THUMBNAIL_SIZE
preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
preview_width, preview_height)
cr = cairo.Context(preview_surface)

scale_w = preview_width * 1.0 / screenshot_width
scale_h = preview_height * 1.0 / screenshot_height
scale = min(scale_w, scale_h)

translate_x = int((preview_width - (screenshot_width * scale)) / 2)
translate_y = int((preview_height - (screenshot_height * scale)) / 2)

cr.translate(translate_x, translate_y)
cr.scale(scale, scale)

cr.set_source_rgba(1, 1, 1, 0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_source_surface(screenshot_surface)
cr.paint()

preview_str = StringIO.StringIO()
preview_surface.write_to_png(preview_str)

return dbus.ByteArray(preview_str.getvalue())