Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--record.py271
-rw-r--r--toolbarcombobox.py59
2 files changed, 198 insertions, 132 deletions
diff --git a/record.py b/record.py
index d957421..363205d 100644
--- a/record.py
+++ b/record.py
@@ -33,9 +33,7 @@ import pygst
pygst.require('0.10')
import gst
-import sugar.profile
from sugar.activity import activity
-from sugar.graphics.icon import Icon
from model import Model
from button import RecdButton
@@ -43,10 +41,17 @@ import constants
from instance import Instance
import utils
from tray import HTray
-from toolbarcombobox import ToolComboBox
+from sugar.graphics.toolcombobox import ToolComboBox
from mediaview import MediaView
import hw
+from sugar.graphics.toolbarbox import ToolbarBox
+from sugar.graphics.toolbarbox import ToolbarButton
+from sugar.graphics.toolbutton import ToolButton
+from sugar.activity.widgets import StopButton
+from sugar.activity.widgets import ActivityToolbarButton
+from sugar.activity.widgets import CopyButton
+
logger = logging.getLogger('record.py')
COLOR_BLACK = gdk.color_parse('#000000')
COLOR_WHITE = gdk.color_parse('#ffffff')
@@ -58,6 +63,7 @@ if logging.getLogger().level <= logging.DEBUG:
else:
gst.debug_set_default_threshold(gst.LEVEL_ERROR)
+
class Record(activity.Activity):
def __init__(self, handle):
super(Record, self).__init__(handle)
@@ -81,7 +87,7 @@ class Record(activity.Activity):
self._media_view.realize_video()
# Changing to the first toolbar kicks off the rest of the setup
- self._toolbox.set_current_toolbar(1)
+ self.model.change_mode(constants.MODE_PHOTO)
def read_file(self, path):
self.model.read_file(path)
@@ -111,31 +117,81 @@ class Record(activity.Activity):
self.connect_after('key-press-event', self._key_pressed)
self._active_toolbar_idx = 0
- self._toolbox = activity.ActivityToolbox(self)
- self.set_toolbox(self._toolbox)
- self._toolbar_modes = [None]
- # remove Toolbox's hardcoded grey separator
- self._toolbox.remove(self._toolbox._separator)
+ self._toolbar_box = ToolbarBox()
+ self.activity_button = ActivityToolbarButton(self)
+ self._toolbar_box.toolbar.insert(self.activity_button, 0)
+ self.set_toolbar_box(self._toolbar_box)
+ self._toolbar = self.get_toolbar_box().toolbar
+
+ edit_button = ToolbarButton()
+ self._edit_toolbar = EditToolbar(self)
+ edit_button.set_page(self._edit_toolbar)
+ edit_button.props.icon_name = 'toolbar-edit'
+ edit_button.props.label = _('Edit')
+ self._toolbar.insert(edit_button, -1)
+
+ view_button = ToolbarButton()
+ self._view_toolbar = ViewToolbar(self)
+ view_button.set_page(self._view_toolbar)
+ view_button.props.icon_name = 'toolbar-view'
+ view_button.props.label = _('View')
+ self._toolbar.insert(view_button, -1)
+
+ self._toolbar.insert(gtk.SeparatorToolItem(), -1)
+
+ self._toolbar_modes = [None]
if self.model.get_has_camera():
self._photo_toolbar = PhotoToolbar()
- self._toolbox.add_toolbar(_('Photo'), self._photo_toolbar)
- self._toolbar_modes.append(constants.MODE_PHOTO)
+ photo_button = ToolbarButton()
+ photo_button.set_page(self._photo_toolbar)
+ photo_button.props.icon_name = 'camera-external'
+ photo_button.props.label = _('Photo')
+ photo_button.mode = constants.MODE_PHOTO
+ photo_button.connect('clicked', self.__mode_button_clicked)
+ # disable auto popup
+ photo_button.get_child().disconnect(
+ photo_button._palette_invoker._enter_hid)
+ self._toolbar.insert(photo_button, -1)
self._video_toolbar = VideoToolbar()
- self._toolbox.add_toolbar(_('Video'), self._video_toolbar)
+ video_button = ToolbarButton()
+ video_button.set_page(self._video_toolbar)
+ video_button.props.icon_name = 'media-video'
+ video_button.props.label = _('Video')
+ video_button.mode = constants.MODE_VIDEO
+ video_button.connect('clicked', self.__mode_button_clicked)
+ # disable auto popup
+ video_button.get_child().disconnect(
+ video_button._palette_invoker._enter_hid)
+ self._toolbar.insert(video_button, -1)
+
+ self._toolbar_modes.append(constants.MODE_PHOTO)
self._toolbar_modes.append(constants.MODE_VIDEO)
else:
self._photo_toolbar = None
self._video_toolbar = None
self._audio_toolbar = AudioToolbar()
- self._toolbox.add_toolbar(_('Audio'), self._audio_toolbar)
+ audio_button = ToolbarButton()
+ audio_button.set_page(self._audio_toolbar)
+ audio_button.props.icon_name = 'media-audio'
+ audio_button.props.label = _('Audio')
+ audio_button.mode = constants.MODE_AUDIO
+ audio_button.connect('clicked', self.__mode_button_clicked)
+ # disable auto popup
+ audio_button.get_child().disconnect(
+ audio_button._palette_invoker._enter_hid)
+ self._toolbar.insert(audio_button, -1)
self._toolbar_modes.append(constants.MODE_AUDIO)
- self._toolbox.show_all()
- self._toolbox.connect("current-toolbar-changed", self._toolbar_changed)
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ separator.set_expand(True)
+ self._toolbar.insert(separator, -1)
+ self._toolbar.insert(StopButton(self), -1)
+ self.get_toolbar_box().show_all()
main_box = gtk.VBox()
self.set_canvas(main_box)
@@ -143,11 +199,16 @@ class Record(activity.Activity):
main_box.show()
self._media_view = MediaView()
- self._media_view.connect('media-clicked', self._media_view_media_clicked)
- self._media_view.connect('pip-clicked', self._media_view_pip_clicked)
- self._media_view.connect('info-clicked', self._media_view_info_clicked)
- self._media_view.connect('full-clicked', self._media_view_full_clicked)
- self._media_view.connect('tags-changed', self._media_view_tags_changed)
+ self._media_view.connect('media-clicked',
+ self._media_view_media_clicked)
+ self._media_view.connect('pip-clicked',
+ self._media_view_pip_clicked)
+ self._media_view.connect('info-clicked',
+ self._media_view_info_clicked)
+ self._media_view.connect('full-clicked',
+ self._media_view_full_clicked)
+ self._media_view.connect('tags-changed',
+ self._media_view_tags_changed)
self._media_view.show()
self._controls_hbox = gtk.HBox()
@@ -155,29 +216,34 @@ class Record(activity.Activity):
self._shutter_button = ShutterButton()
self._shutter_button.connect("clicked", self._shutter_clicked)
- self._controls_hbox.pack_start(self._shutter_button, expand=True, fill=False)
+ self._controls_hbox.pack_start(self._shutter_button, expand=True,
+ fill=False)
self._countdown_image = CountdownImage()
- self._controls_hbox.pack_start(self._countdown_image, expand=True, fill=False)
+ self._controls_hbox.pack_start(self._countdown_image, expand=True,
+ fill=False)
self._play_button = PlayButton()
self._play_button.connect('clicked', self._play_pause_clicked)
self._controls_hbox.pack_start(self._play_button, expand=False)
self._playback_scale = PlaybackScale(self.model)
- self._controls_hbox.pack_start(self._playback_scale, expand=True, fill=True)
+ self._controls_hbox.pack_start(self._playback_scale, expand=True,
+ fill=True)
self._progress = ProgressInfo()
self._controls_hbox.pack_start(self._progress, expand=True, fill=True)
self._title_label = gtk.Label()
- self._title_label.set_markup("<b><span foreground='white'>"+_('Title:')+'</span></b>')
+ self._title_label.set_markup("<b><span foreground='white'>" +
+ _('Title:') + '</span></b>')
self._controls_hbox.pack_start(self._title_label, expand=False)
self._title_entry = gtk.Entry()
self._title_entry.modify_bg(gtk.STATE_INSENSITIVE, COLOR_BLACK)
self._title_entry.connect('changed', self._title_changed)
- self._controls_hbox.pack_start(self._title_entry, expand=True, fill=True, padding=10)
+ self._controls_hbox.pack_start(self._title_entry, expand=True,
+ fill=True, padding=10)
container = RecordContainer(self._media_view, self._controls_hbox)
main_box.pack_start(container, expand=True, fill=True, padding=6)
@@ -222,11 +288,11 @@ class Record(activity.Activity):
key = event.keyval
- if key == gtk.keysyms.KP_Page_Up: # game key O
+ if key == gtk.keysyms.KP_Page_Up: # game key O
if self._shutter_button.props.visible:
if self._shutter_button.props.sensitive:
self._shutter_button.clicked()
- else: # return to live mode
+ else: # return to live mode
self.model.set_state(constants.STATE_READY)
elif key == gtk.keysyms.c and event.state == gdk.CONTROL_MASK:
self._copy_to_clipboard(self._active_recd)
@@ -287,7 +353,8 @@ class Record(activity.Activity):
self._active_recd.setTitle(self._title_entry.get_text())
def _media_view_media_clicked(self, widget):
- if self._play_button.props.visible and self._play_button.props.sensitive:
+ if self._play_button.props.visible and \
+ self._play_button.props.sensitive:
self._play_button.clicked()
def _media_view_pip_clicked(self, widget):
@@ -307,7 +374,8 @@ class Record(activity.Activity):
return
self._showing_info = True
- if self.model.get_mode() in (constants.MODE_PHOTO, constants.MODE_AUDIO):
+ if self.model.get_mode() in (constants.MODE_PHOTO,
+ constants.MODE_AUDIO):
func = self._media_view.show_info_photo
else:
func = self._media_view.show_info_video
@@ -319,38 +387,41 @@ class Record(activity.Activity):
self._title_entry.show()
self._title_label.show()
- func(recd.recorderName, recd.colorStroke, recd.colorFill, utils.getDateString(recd.time), recd.tags)
+ func(recd.recorderName, recd.colorStroke, recd.colorFill,
+ utils.getDateString(recd.time), recd.tags)
def _media_view_full_clicked(self, widget):
self._toggle_fullscreen()
def _media_view_tags_changed(self, widget, tbuffer):
- text = tbuffer.get_text(tbuffer.get_start_iter(), tbuffer.get_end_iter())
+ text = tbuffer.get_text(tbuffer.get_start_iter(),
+ tbuffer.get_end_iter())
self._active_recd.setTags(text)
def _toggle_fullscreen(self):
if not self._fullscreen:
- self._toolbox.hide()
+ self._toolbar_box.hide()
self._thumb_tray.hide()
else:
- self._toolbox.show()
+ self._toolbar_box.show()
self._thumb_tray.show()
self._fullscreen = not self._fullscreen
self._media_view.set_fullscreen(self._fullscreen)
- def _toolbar_changed(self, toolbox, num):
- if num == 0: # Activity tab
- return
-
+ def __mode_button_clicked(self, button):
# Prevent mode/tab changing under certain conditions by immediately
# changing back to the previously-selected toolbar
+ """
if self.model.ui_frozen():
self._toolbox.set_current_toolbar(self._active_toolbar_idx)
return
self._active_toolbar_idx = num
self.model.change_mode(self._toolbar_modes[num])
+ """
+ if not self.model.ui_frozen():
+ self.model.change_mode(button.mode)
def _shutter_clicked(self, arg):
self.model.do_shutter()
@@ -368,13 +439,15 @@ class Record(activity.Activity):
self._play_button.hide()
self._playback_scale.hide()
self._progress.hide()
- self._controls_hbox.set_child_packing(self._shutter_button, expand=True, fill=False, padding=0, pack_type=gtk.PACK_START)
+ self._controls_hbox.set_child_packing(self._shutter_button,
+ expand=True, fill=False, padding=0, pack_type=gtk.PACK_START)
self._shutter_button.set_normal()
self._shutter_button.show()
self._media_view.show_live()
elif state == constants.STATE_RECORDING:
self._shutter_button.set_recording()
- self._controls_hbox.set_child_packing(self._shutter_button, expand=False, fill=False, padding=0, pack_type=gtk.PACK_START)
+ self._controls_hbox.set_child_packing(self._shutter_button,
+ expand=False, fill=False, padding=0, pack_type=gtk.PACK_START)
self._progress.show()
elif state == constants.STATE_PROCESSING:
self._set_cursor_busy()
@@ -399,10 +472,13 @@ class Record(activity.Activity):
def add_thumbnail(self, recd, scroll_to_end):
button = RecdButton(recd)
- clicked_handler = button.connect("clicked", self._thumbnail_clicked, recd)
+ clicked_handler = button.connect("clicked", self._thumbnail_clicked,
+ recd)
remove_handler = button.connect("remove-requested", self._remove_recd)
- clipboard_handler = button.connect("copy-clipboard-requested", self._thumbnail_copy_clipboard)
- button.set_data('handler-ids', (clicked_handler, remove_handler, clipboard_handler))
+ clipboard_handler = button.connect("copy-clipboard-requested",
+ self._thumbnail_copy_clipboard)
+ button.set_data('handler-ids', (clicked_handler, remove_handler,
+ clipboard_handler))
self._thumb_tray.add_item(button)
button.show()
if scroll_to_end:
@@ -417,7 +493,8 @@ class Record(activity.Activity):
media_path = recd.getMediaFilepath()
tmp_path = utils.getUniqueFilepath(media_path, 0)
shutil.copyfile(media_path, tmp_path)
- gtk.Clipboard().set_with_data([('text/uri-list', 0, 0)], self._clipboard_get, self._clipboard_clear, tmp_path)
+ gtk.Clipboard().set_with_data([('text/uri-list', 0, 0)],
+ self._clipboard_get, self._clipboard_clear, tmp_path)
def _clipboard_get(self, clipboard, selection_data, info, path):
selection_data.set("text/uri-list", 8, "file://" + path)
@@ -493,7 +570,7 @@ class Record(activity.Activity):
#downloading = self.ca.requestMeshDownload(recd)
#self.MESHING = downloading
- if True: #not downloading:
+ if True: # not downloading:
#self.progressWindow.updateProgress(0, "")
return recd.getMediaFilepath()
@@ -536,6 +613,7 @@ class Record(activity.Activity):
def _set_cursor_default(self):
self.window.set_cursor(None)
+
class RecordContainer(gtk.Container):
"""
A custom Container that contains a media view area, and a controls hbox.
@@ -573,7 +651,8 @@ class RecordContainer(gtk.Container):
height=self.allocation.height,
wclass=gdk.INPUT_OUTPUT,
colormap=self.get_colormap(),
- event_mask=self.get_events() | gdk.VISIBILITY_NOTIFY_MASK | gdk.EXPOSURE_MASK)
+ event_mask=self.get_events() | gdk.VISIBILITY_NOTIFY_MASK | \
+ gdk.EXPOSURE_MASK)
self.window.set_user_data(self)
self.set_style(self.style.attach(self.window))
@@ -603,8 +682,9 @@ class RecordContainer(gtk.Container):
@staticmethod
def _constrain_4_3(width, height):
- if (width % 4 == 0) and (height % 3 == 0) and ((width / 4) * 3) == height:
- return width, height # nothing to do
+ if (width % 4 == 0) and (height % 3 == 0) and \
+ ((width / 4) * 3) == height:
+ return width, height # nothing to do
ratio = 4.0 / 3.0
if ratio * height > width:
@@ -614,7 +694,7 @@ class RecordContainer(gtk.Container):
height = (height / 3) * 3
width = int(ratio * height)
- return width, height
+ return width, height
@staticmethod
def _center_in_plane(plane_size, size):
@@ -627,9 +707,12 @@ class RecordContainer(gtk.Container):
remaining_height = self.allocation.height - self._controls_hbox_height
# give the mediaview the rest, constrained to 4/3 and centered
- media_view_width, media_view_height = self._constrain_4_3(self.allocation.width, remaining_height)
- media_view_x = self._center_in_plane(self.allocation.width, media_view_width)
- media_view_y = self._center_in_plane(remaining_height, media_view_height)
+ media_view_width, media_view_height = \
+ self._constrain_4_3(self.allocation.width, remaining_height)
+ media_view_x = self._center_in_plane(
+ self.allocation.width, media_view_width)
+ media_view_y = self._center_in_plane(
+ remaining_height, media_view_height)
# send allocation to mediaview
alloc = gdk.Rectangle()
@@ -655,11 +738,13 @@ class RecordContainer(gtk.Container):
for widget in (self._media_view, self._controls_hbox):
callback(widget, data)
+
class PlaybackScale(gtk.HScale):
def __init__(self, model):
self.model = model
self._change_handler = None
- self._playback_adjustment = gtk.Adjustment(0.0, 0.00, 100.0, 0.1, 1.0, 1.0)
+ self._playback_adjustment = gtk.Adjustment(0.0, 0.00, 100.0, 0.1, \
+ 1.0, 1.0)
super(PlaybackScale, self).__init__(self._playback_adjustment)
self.set_draw_value(False)
@@ -675,7 +760,8 @@ class PlaybackScale(gtk.HScale):
def _button_press(self, widget, event):
self.model.start_seek()
- self._change_handler = self.connect('value-changed', self._value_changed)
+ self._change_handler = self.connect('value-changed',
+ self._value_changed)
def _button_release(self, widget, event):
self.disconnect(self._change_handler)
@@ -816,19 +902,6 @@ class RecordToolbar(gtk.Toolbar):
def __init__(self, icon_name, with_quality, with_timer, with_duration):
super(RecordToolbar, self).__init__()
- img = Icon(icon_name=icon_name)
- color = sugar.profile.get_color()
- img.set_property('fill-color', color.get_fill_color())
- img.set_property('stroke-color', color.get_stroke_color())
- toolitem = gtk.ToolItem()
- toolitem.add(img)
- self.insert(toolitem, -1)
-
- separator = gtk.SeparatorToolItem()
- separator.set_draw(False)
- separator.set_expand(True)
- self.insert(separator, -1)
-
if with_quality:
combo = gtk.combo_box_new_text()
self.quality = ToolComboBox(combo=combo, label_text=_('Quality:'))
@@ -847,6 +920,7 @@ class RecordToolbar(gtk.Toolbar):
if with_duration:
self._duration_combo = DurationCombo()
self.insert(self._duration_combo, -1)
+ self.show_all()
def get_timer(self):
return self._timer_combo.get_value()
@@ -872,19 +946,23 @@ class RecordToolbar(gtk.Toolbar):
def set_quality(self, idx):
self.quality.combo.set_active(idx)
+
class PhotoToolbar(RecordToolbar):
def __init__(self):
- super(PhotoToolbar, self).__init__('media-photo', with_quality=False, with_timer=True, with_duration=False)
+ super(PhotoToolbar, self).__init__('media-photo', with_quality=False,
+ with_timer=True, with_duration=False)
class VideoToolbar(RecordToolbar):
def __init__(self):
- super(VideoToolbar, self).__init__('media-video', with_quality=True, with_timer=True, with_duration=True)
+ super(VideoToolbar, self).__init__('media-video', with_quality=True,
+ with_timer=True, with_duration=True)
class AudioToolbar(RecordToolbar):
def __init__(self):
- super(AudioToolbar, self).__init__('media-audio', with_quality=False, with_timer=True, with_duration=True)
+ super(AudioToolbar, self).__init__('media-audio', with_quality=False,
+ with_timer=True, with_duration=True)
class TimerCombo(ToolComboBox):
@@ -892,8 +970,9 @@ class TimerCombo(ToolComboBox):
def __init__(self):
self._combo_box_text = gtk.combo_box_new_text()
- super(TimerCombo, self).__init__(combo=self._combo_box_text, label_text=_('Timer:'))
-
+ super(TimerCombo, self).__init__(combo=self._combo_box_text,
+ label_text=_('Timer:'))
+
for i in self.TIMERS:
if i == 0:
self._combo_box_text.append_text(_('Immediate'))
@@ -903,7 +982,7 @@ class TimerCombo(ToolComboBox):
self._combo_box_text.set_active(0)
def get_value(self):
- return TimerCombo.TIMERS[self._combo_box_text.get_active()]
+ return TimerCombo.TIMERS[self._combo_box_text.get_active()]
def get_value_idx(self):
return self._combo_box_text.get_active()
@@ -921,7 +1000,8 @@ class DurationCombo(ToolComboBox):
def __init__(self):
self._combo_box_text = gtk.combo_box_new_text()
- super(DurationCombo, self).__init__(combo=self._combo_box_text, label_text=_('Duration:'))
+ super(DurationCombo, self).__init__(combo=self._combo_box_text,
+ label_text=_('Duration:'))
for i in self.DURATIONS:
string = DurationCombo._minutes_string(i)
@@ -941,3 +1021,48 @@ class DurationCombo(ToolComboBox):
def _minutes_string(x):
return ngettext('%s minute', '%s minutes', x) % x
+
+class EditToolbar(gtk.Toolbar):
+
+ def __init__(self, record_activity):
+ gtk.Toolbar.__init__(self)
+ self._activity = record_activity
+ self.copy = CopyButton()
+ self.insert(self.copy, -1)
+ self.copy.show()
+ self.copy.connect('clicked', self.__copy_clicked)
+
+ def __copy_clicked(self, button):
+ self._activity._copy_to_clipboard(self._activity._active_recd)
+
+
+class ViewToolbar(gtk.Toolbar):
+
+ def __init__(self, record_activity):
+ gtk.Toolbar.__init__(self)
+ self._activity = record_activity
+
+ full_screen_button = ToolButton('view-fullscreen')
+ full_screen_button.props.label = _('Fullscreen')
+ self.insert(full_screen_button, -1)
+ full_screen_button.connect('clicked', self.__fullscreen_clicked)
+
+ tray_button = ToolButton('tray-hide')
+ tray_button.props.label = _('Hide tray')
+ tray_button.connect('clicked', self.__tray_clicked_cb)
+ self.insert(tray_button, -1)
+
+ self.show_all()
+
+ def __fullscreen_clicked(self, button):
+ self._activity._toggle_fullscreen()
+
+ def __tray_clicked_cb(self, button):
+ if self._activity._thumb_tray.props.visible is False:
+ self._activity._thumb_tray.show()
+ button.set_icon('tray-hide')
+ button.set_tooltip(_('Hide Tray'))
+ else:
+ self._activity._thumb_tray.hide()
+ button.set_icon('tray-show')
+ button.set_tooltip(_('Show Tray'))
diff --git a/toolbarcombobox.py b/toolbarcombobox.py
deleted file mode 100644
index e455414..0000000
--- a/toolbarcombobox.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) 2007, Red Hat, Inc.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-import gtk
-import gobject
-
-from sugar.graphics.combobox import ComboBox
-from sugar.graphics import style
-
-class ToolComboBox(gtk.ToolItem):
- __gproperties__ = {
- 'label-text' : (str, None, None, None,
- gobject.PARAM_WRITABLE),
- }
-
- def __init__(self, combo=None, **kwargs):
- self.label = None
- self._label_text = ''
-
- gobject.GObject.__init__(self, **kwargs)
-
- self.set_border_width(int(style.DEFAULT_PADDING*3.5))
-
- hbox = gtk.HBox(False, style.DEFAULT_SPACING)
-
- self.label = gtk.Label(self._label_text)
- hbox.pack_start(self.label, False)
- self.label.show()
-
- if combo:
- self.combo = combo
- else:
- self.combo = ComboBox()
-
- hbox.pack_start(self.combo)
- self.combo.show()
-
- self.add(hbox)
- hbox.show()
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'label-text':
- self._label_text = value
- if self.label:
- self.label.set_text(self._label_text)