gnomemm r1932 - in cluttermm_tutorial/trunk: . examples/multiline_text_entry
- From: daniel svn gnome org
- To: svn-commits-list gnome org
- Subject: gnomemm r1932 - in cluttermm_tutorial/trunk: . examples/multiline_text_entry
- Date: Wed, 31 Dec 2008 18:02:50 +0000 (UTC)
Author: daniel
Date: Wed Dec 31 18:02:50 2008
New Revision: 1932
URL: http://svn.gnome.org/viewvc/gnomemm?rev=1932&view=rev
Log:
* examples/multiline_text_entry/{multiline_entry.{cc,h},main.cc}:
New example implementing a multi-line text entry actor. Converted
from the C Clutter tutorial example of the same name.
* Makefile.am (bin_PROGRAMS): Add
examples/multiline_text_entry/example.
Added:
cluttermm_tutorial/trunk/examples/multiline_text_entry/
cluttermm_tutorial/trunk/examples/multiline_text_entry/main.cc
cluttermm_tutorial/trunk/examples/multiline_text_entry/multiline_entry.cc
cluttermm_tutorial/trunk/examples/multiline_text_entry/multiline_entry.h
Modified:
cluttermm_tutorial/trunk/ChangeLog
cluttermm_tutorial/trunk/Makefile.am
Modified: cluttermm_tutorial/trunk/Makefile.am
==============================================================================
--- cluttermm_tutorial/trunk/Makefile.am (original)
+++ cluttermm_tutorial/trunk/Makefile.am Wed Dec 31 18:02:50 2008
@@ -35,6 +35,7 @@
examples/custom_container/example \
examples/effects/example \
examples/full_example/example \
+ examples/multiline_text_entry/example \
examples/score/example \
examples/scrolling/example \
examples/stage/example \
@@ -55,6 +56,10 @@
examples/custom_container/main.cc
examples_effects_example_SOURCES = examples/effects/main.cc
examples_full_example_example_SOURCES = examples/full_example/main.cc
+examples_multiline_text_entry_example_SOURCES = \
+ examples/multiline_text_entry/main.cc \
+ examples/multiline_text_entry/multiline_entry.cc\
+ examples/multiline_text_entry/multiline_entry.h
examples_score_example_SOURCES = examples/score/main.cc
examples_scrolling_example_SOURCES = \
examples/scrolling/main.cc \
Added: cluttermm_tutorial/trunk/examples/multiline_text_entry/main.cc
==============================================================================
--- (empty file)
+++ cluttermm_tutorial/trunk/examples/multiline_text_entry/main.cc Wed Dec 31 18:02:50 2008
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008 Openismus GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "multiline_entry.h"
+#include <cluttermm.h>
+#include <pangomm/init.h>
+
+int main(int argc, char** argv)
+{
+ Pango::init();
+ Clutter::init(&argc, &argv);
+
+ // Get the stage and set its size and color
+ const Glib::RefPtr<Clutter::Stage> stage = Clutter::Stage::get_default();
+ stage->set_size(400, 400);
+ stage->set_color(Clutter::Color(0x00, 0x00, 0x00, 0xFF)); // black
+
+ // Add our multiline entry to the stage
+ const Glib::RefPtr<Tutorial::MultilineEntry>
+ multiline = Tutorial::MultilineEntry::create();
+ multiline->set_text(
+ "And as I sat there brooding on the old, unknown world, I thought of "
+ "Gatsby's wonder when he first picked out the green light at the end of "
+ "Daisy's dock. He had come a long way to this blue lawn and his dream "
+ "must have seemed so close that he could hardly fail to grasp it. He did "
+ "not know that it was already behind him, somewhere back in that vast "
+ "obscurity beyond the city, where the dark fields of the republic rolled "
+ "on under the night.");
+ multiline->set_color(Clutter::Color(0xAE, 0xFF, 0x7F, 0xFF));
+ multiline->set_size(380, 380);
+ multiline->set_position(10, 10);
+ stage->add_actor(multiline);
+ multiline->show();
+
+ // Connect signal handlers to handle key presses on the stage
+ stage->signal_key_press_event().connect(
+ sigc::mem_fun(*multiline.operator->(), &Tutorial::MultilineEntry::handle_key_event));
+
+ stage->show();
+
+ // Start the main loop, so we can respond to events
+ Clutter::main();
+
+ return 0;
+}
Added: cluttermm_tutorial/trunk/examples/multiline_text_entry/multiline_entry.cc
==============================================================================
--- (empty file)
+++ cluttermm_tutorial/trunk/examples/multiline_text_entry/multiline_entry.cc Wed Dec 31 18:02:50 2008
@@ -0,0 +1,437 @@
+/* Copyright 2008 Openismus GmbH,
+ * based on ClutterEntry in Clutter, Copyright OpenedHand
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "multiline_entry.h"
+#include <cogl/cogl.h>
+#include <cogl/cogl-pango.h>
+
+namespace
+{
+
+static const char *const default_font_name = "Sans 10";
+
+enum { ENTRY_CURSOR_WIDTH = 1 };
+
+static Glib::RefPtr<Pango::Context> ref_shared_context()
+{
+ static void* context = 0;
+
+ if (context == 0)
+ {
+ double resolution = clutter_backend_get_resolution(clutter_get_default_backend());
+
+ if (resolution < 0.0)
+ resolution = 96.0; // fallback
+
+ PangoFontMap *const fontmap = cogl_pango_font_map_new();
+ cogl_pango_font_map_set_resolution(COGL_PANGO_FONT_MAP(fontmap), resolution);
+
+ context = cogl_pango_font_map_create_context(COGL_PANGO_FONT_MAP(fontmap));
+
+ // Clear the pointer when the object is destroyed
+ g_object_add_weak_pointer(static_cast<GObject*>(context), &context);
+
+ // Transfer ownership
+ return Glib::wrap(static_cast<PangoContext*>(context), false);
+ }
+
+ // Increase reference count
+ return Glib::wrap(static_cast<PangoContext*>(context), true);
+}
+
+} // anonymous namespace
+
+namespace Tutorial
+{
+
+/*
+ * Example of a multi-line text entry actor, based on ClutterEntry.
+ */
+
+MultilineEntry::MultilineEntry()
+:
+ context_ (ref_shared_context()),
+ font_ (default_font_name),
+ fgcol_ (0x00, 0x00, 0x00, 0xFF),
+ text_ (),
+ width_ (0),
+ position_ (Glib::ustring::npos),
+ text_x_ (0),
+ effective_attrs_ (),
+ layout_ (),
+ cursor_pos_ (),
+ cursor_ (Clutter::Rectangle::create(fgcol_))
+{
+ signal_text_changed_.connect(sigc::mem_fun(*this, &MultilineEntry::on_text_changed));
+ signal_cursor_event_.connect(sigc::mem_fun(*this, &MultilineEntry::on_cursor_event));
+ signal_activate_ .connect(sigc::mem_fun(*this, &MultilineEntry::on_activate));
+
+ cursor_->set_parent(Glib::RefPtr<Clutter::Actor>((reference(), this)));
+
+ // We use the font size to set the default width and height, in case
+ // the user doesn't call Clutter::Actor::set_size().
+ const double font_size = font_.get_size() * context_->get_resolution() / (72.0 * Pango::SCALE);
+
+ set_size(20 * int(font_size), 50);
+}
+
+MultilineEntry::~MultilineEntry()
+{}
+
+Glib::RefPtr<MultilineEntry> MultilineEntry::create()
+{
+ return Glib::RefPtr<MultilineEntry>(new MultilineEntry());
+}
+
+void MultilineEntry::set_text(const Glib::ustring& text)
+{
+ text_ = text;
+ layout_.clear();
+ cursor_pos_.set_width(0);
+
+ if (is_visible())
+ queue_redraw();
+
+ signal_text_changed_.emit();
+}
+
+Glib::ustring MultilineEntry::get_text() const
+{
+ return text_;
+}
+
+/*
+ * Sets font_name as the font used by entry. font_name must be a string
+ * containing the font name and its size, similarly to what you would feed
+ * to the Pango::FontDescription constructor.
+ */
+void MultilineEntry::set_font_name(const Glib::ustring& font_name)
+{
+ Pango::FontDescription font ((font_name.empty()) ? Glib::ustring(default_font_name) : font_name);
+
+ if (font == font_)
+ return;
+
+ swap(font_, font);
+
+ if (!text_.empty())
+ {
+ layout_.clear();
+
+ if (is_visible())
+ queue_redraw();
+ }
+}
+
+Glib::ustring MultilineEntry::get_font_name() const
+{
+ return font_.to_string();
+}
+
+void MultilineEntry::set_color(const Clutter::Color& color)
+{
+ fgcol_ = color;
+ set_opacity(fgcol_.get_alpha());
+
+ cursor_->set_color(fgcol_);
+
+ if (is_visible())
+ queue_redraw();
+}
+
+Clutter::Color MultilineEntry::get_color() const
+{
+ return fgcol_;
+}
+
+void MultilineEntry::on_text_changed()
+{}
+
+void MultilineEntry::on_cursor_event(Clutter::Geometry&)
+{}
+
+void MultilineEntry::on_activate()
+{}
+
+/*
+ * Characters are removed from before the current position of the cursor.
+ */
+void MultilineEntry::delete_chars(Glib::ustring::size_type num)
+{
+ using Glib::ustring;
+
+ const ustring::size_type len = text_.length();
+ const ustring::size_type end = (position_ == ustring::npos) ? len : std::min(position_, len);
+ const ustring::size_type start = (num < end) ? end - num : 0;
+
+ set_text(ustring(text_).erase(start, end - start));
+
+ if (position_ != ustring::npos)
+ set_cursor_position(start);
+}
+
+void MultilineEntry::ensure_layout(int width)
+{
+ if (!layout_)
+ {
+ Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context_);
+
+ layout->set_attributes(effective_attrs_);
+ layout->set_single_paragraph_mode(false);
+ layout->set_font_description(font_);
+ layout->set_wrap(Pango::WRAP_WORD);
+ layout->set_width((width > 0) ? width * Pango::SCALE : -1);
+ layout->set_text(text_);
+
+ swap(layout_, layout);
+ }
+}
+
+void MultilineEntry::ensure_cursor_position()
+{
+
+ Glib::ustring::iterator pos = text_.begin();
+
+ if (position_ == Glib::ustring::npos)
+ pos = text_.end();
+ else
+ std::advance(pos, position_);
+
+ const Pango::Rectangle rect = layout_->get_cursor_strong_pos(pos.base() - text_.begin().base());
+
+ cursor_pos_.set_xy(rect.get_x() / Pango::SCALE, rect.get_y() / Pango::SCALE);
+ cursor_pos_.set_size(ENTRY_CURSOR_WIDTH, rect.get_height() / Pango::SCALE);
+
+ signal_cursor_event_.emit(sigc::ref(cursor_pos_));
+}
+
+/*
+ * Sets the position of the cursor. The position must be less than or
+ * equal to the number of characters in the entry. A value of npos indicates
+ * that the position should be set after the last character in the entry.
+ * Note that this position is in characters, not in bytes.
+ */
+void MultilineEntry::set_cursor_position(Glib::ustring::size_type position)
+{
+ if (position < text_.length())
+ position_ = position;
+ else
+ position_ = Glib::ustring::npos;
+
+ cursor_pos_.set_width(0);
+
+ if (is_visible())
+ queue_redraw();
+}
+
+/*
+ * Insert a character to the right of the current position of the cursor,
+ * and update the position of the cursor.
+ */
+void MultilineEntry::insert_unichar(gunichar wc)
+{
+ g_return_if_fail(Glib::Unicode::validate(wc));
+
+ if (wc == 0)
+ return;
+
+ using Glib::ustring;
+
+ if (position_ == ustring::npos)
+ set_text(text_ + wc);
+ else
+ set_text(ustring(text_).insert(position_, 1, wc));
+
+ if (position_ != ustring::npos)
+ set_cursor_position(position_ + 1);
+}
+
+/*
+ * Deletes a sequence of characters. The characters that are deleted are
+ * those characters at positions from start_pos up to, but not including,
+ * end_pos. If end_pos is npos, then the characters deleted will be
+ * those characters from start_pos to the end of the text.
+ */
+void MultilineEntry::delete_text(Glib::ustring::size_type start_pos,
+ Glib::ustring::size_type end_pos)
+{
+ using Glib::ustring;
+
+ set_text(ustring(text_).erase(start_pos, (end_pos == ustring::npos) ? ustring::npos
+ : end_pos - start_pos));
+}
+
+void MultilineEntry::paint_cursor_vfunc()
+{
+ cursor_->set_geometry(cursor_pos_);
+ cursor_->paint();
+}
+
+void MultilineEntry::on_paint()
+{
+ const int width = (width_ < 0) ? get_width() : width_;
+ set_clip(0, 0, width, get_height());
+
+ int actor_width = width;
+
+ ensure_layout(actor_width);
+ ensure_cursor_position();
+
+ const Pango::Rectangle logical = layout_->get_logical_extents();
+ int text_width = logical.get_width() / Pango::SCALE;
+
+ if (actor_width < text_width)
+ {
+ // We need to do some scrolling
+ const int cursor_x = cursor_pos_.get_x();
+
+ // If the cursor is at the begining or the end of the text, the placement
+ // is easy, however, if the cursor is in the middle somewhere, we need to
+ // make sure the text doesn't move until the cursor is either in the
+ // far left or far right
+ if (position_ == 0)
+ {
+ text_x_ = 0;
+ }
+ else if (position_ == Glib::ustring::npos)
+ {
+ text_x_ = actor_width - text_width;
+ cursor_pos_.set_x(cursor_x + text_x_);
+ }
+ else
+ {
+ if (text_x_ <= 0)
+ {
+ const int diff = -text_x_;
+
+ if (cursor_x < diff)
+ text_x_ += diff - cursor_x;
+ else if (cursor_x > diff + actor_width)
+ text_x_ -= cursor_x - (diff + actor_width);
+ }
+ cursor_pos_.set_x(cursor_x + text_x_);
+ }
+ }
+ else
+ {
+ text_x_ = 0;
+ }
+
+ CoglColor color;
+
+ cogl_color_set_from_4ub(&color, fgcol_.get_red(),
+ fgcol_.get_green(),
+ fgcol_.get_blue(),
+ get_opacity());
+ cogl_pango_render_layout(layout_->gobj(), text_x_, 0, &color, 0);
+
+ paint_cursor_vfunc();
+}
+
+void MultilineEntry::allocate_vfunc(const Clutter::ActorBox& box, bool absolute_origin_changed)
+{
+ const int width = CLUTTER_UNITS_TO_DEVICE(box.get_x2() - box.get_x1());
+
+ if (width_ != width)
+ {
+ layout_.clear();
+ ensure_layout(width);
+
+ width_ = width;
+ }
+
+ Clutter::Actor::allocate_vfunc(box, absolute_origin_changed);
+}
+
+/*
+ * This method will handle a Clutter::KeyEvent, like those returned in a
+ * key-press/release-event, and will translate it for the entry. This includes
+ * non-alphanumeric keys, such as the arrows keys, which will move the
+ * input cursor. You should use this function inside a handler for the
+ * Clutter::Stage::signal_key_press_event() or
+ * Clutter::Stage::signal_key_release_event().
+ */
+bool MultilineEntry::handle_key_event(Clutter::KeyEvent* event)
+{
+ switch (Clutter::key_event_symbol(event))
+ {
+ case CLUTTER_Escape:
+ case CLUTTER_Shift_L:
+ case CLUTTER_Shift_R:
+ // Ignore these - Don't try to insert them as characters
+ return false;
+
+ case CLUTTER_BackSpace:
+ // Delete the current character
+ if (position_ != 0 && !text_.empty())
+ delete_chars(1);
+ break;
+
+ case CLUTTER_Delete:
+ case CLUTTER_KP_Delete:
+ // Delete the current character
+ if (!text_.empty() && position_ != Glib::ustring::npos)
+ delete_text(position_, position_ + 1);
+ break;
+
+ case CLUTTER_Left:
+ case CLUTTER_KP_Left:
+ // Move the cursor one character left
+ if (position_ != 0 && !text_.empty())
+ set_cursor_position(((position_ == Glib::ustring::npos) ? text_.length() : position_) - 1);
+ break;
+
+ case CLUTTER_Right:
+ case CLUTTER_KP_Right:
+ // Move the cursor one character right
+ if (position_ != Glib::ustring::npos && !text_.empty() && position_ < text_.length())
+ set_cursor_position(position_ + 1);
+ break;
+
+ case CLUTTER_Up:
+ case CLUTTER_KP_Up:
+ // TODO: Calculate the index of the position on the line above,
+ // and set the cursor to it.
+ break;
+
+ case CLUTTER_Down:
+ case CLUTTER_KP_Down:
+ // TODO: Calculate the index of the position on the line below,
+ // and set the cursor to it.
+ break;
+
+ case CLUTTER_End:
+ case CLUTTER_KP_End:
+ // Move the cursor to the end of the text
+ set_cursor_position(Glib::ustring::npos);
+ break;
+
+ case CLUTTER_Begin:
+ case CLUTTER_Home:
+ case CLUTTER_KP_Home:
+ // Move the cursor to the start of the text
+ set_cursor_position(0);
+ break;
+
+ default:
+ insert_unichar(Clutter::key_event_unicode(event));
+ break;
+ }
+ return true;
+}
+
+} // namespace Tutorial
Added: cluttermm_tutorial/trunk/examples/multiline_text_entry/multiline_entry.h
==============================================================================
--- (empty file)
+++ cluttermm_tutorial/trunk/examples/multiline_text_entry/multiline_entry.h Wed Dec 31 18:02:50 2008
@@ -0,0 +1,90 @@
+/* Copyright 2008 Openismus GmbH,
+ * based on ClutterEntry in Clutter, Copyright OpenedHand
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef CLUTTER_TUTORIAL_MULTILINE_ENTRY_H
+#define CLUTTER_TUTORIAL_MULTILINE_ENTRY_H
+
+#include <cluttermm.h>
+#include <pangomm.h>
+
+namespace Tutorial
+{
+
+class MultilineEntry : public Clutter::Actor
+{
+public:
+ virtual ~MultilineEntry();
+ static Glib::RefPtr<MultilineEntry> create();
+
+ sigc::signal<void>& signal_text_changed() { return signal_text_changed_; }
+ sigc::signal<void, Clutter::Geometry&>& signal_cursor_event() { return signal_cursor_event_; }
+ sigc::signal<void>& signal_activate() { return signal_activate_; }
+
+ void set_text(const Glib::ustring& text);
+ Glib::ustring get_text() const;
+
+ void set_font_name(const Glib::ustring& font_name);
+ Glib::ustring get_font_name() const;
+
+ void set_color(const Clutter::Color& color);
+ Clutter::Color get_color() const;
+
+ bool handle_key_event(Clutter::KeyEvent* event);
+
+protected:
+ MultilineEntry();
+
+ virtual void on_paint();
+ virtual void allocate_vfunc(const Clutter::ActorBox& box, bool absolute_origin_changed);
+
+ virtual void paint_cursor_vfunc();
+ virtual void on_text_changed();
+ virtual void on_cursor_event(Clutter::Geometry& geometry);
+ virtual void on_activate();
+
+private:
+ sigc::signal<void> signal_text_changed_;
+ sigc::signal<void, Clutter::Geometry&> signal_cursor_event_;
+ sigc::signal<void> signal_activate_;
+
+ Glib::RefPtr<Pango::Context> context_;
+ Pango::FontDescription font_;
+
+ Clutter::Color fgcol_;
+ Glib::ustring text_;
+
+ int width_;
+ Glib::ustring::size_type position_;
+ int text_x_;
+
+ Pango::AttrList effective_attrs_;
+ Glib::RefPtr<Pango::Layout> layout_;
+
+ Clutter::Geometry cursor_pos_;
+ Glib::RefPtr<Clutter::Rectangle> cursor_;
+
+ void ensure_layout(int width);
+ void ensure_cursor_position();
+ void set_cursor_position(Glib::ustring::size_type position);
+ void insert_unichar(gunichar wc);
+ void delete_chars(Glib::ustring::size_type num);
+ void delete_text(Glib::ustring::size_type start_pos, Glib::ustring::size_type end_pos);
+};
+
+} // namespace Tutorial
+
+#endif /* !CLUTTER_TUTORIAL_MULTILINE_ENTRY_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]