أعجوبة

البرمجيات الحُرة والمفتوحة المصدر

أدوات المستخدم

أدوات الموقع


docs:cairographics

اختلافات

عرض الاختلافات بين النسخة المختارة و النسخة الحالية من الصفحة.

رابط إلى هذه المقارنة

جانبي المراجعة السابقةالمراجعة السابقة
docs:cairographics [2009/06/26 09:49] ayoussefdocs:cairographics [2015/04/23 03:19] (حالي) – تحرير خارجي 127.0.0.1
سطر 1: سطر 1:
 +{{tag>مقالات مترجمة برمجة رسم متجهي سي cairo grpagics}}
 +~~ODT~~
 +
 +====== مكتبة الرسم المتجهي Cairo ======
 +
 +  * مقالة من تأليف Jan Bodnar
 +  * المصدر http://zetcode.com/tutorials/cairographicstutorial/
 +  * ترجمة //**احمد يوسف**//
 +  * قيد المراجعة
 +
 +هذه دروس عن كايرو تم كتابتها بلغة سي، ومناسبة للمطورين مبتدأين ومتوسطين. لاتنس الإطلاع على دروس GTK+
 +
 +
 +===== كايرو مكتبة الرسوميات =====
 +
 +
 +مرحبا بك فى دروس كايرو، فى هذه الدروس ستتعلم الأساسيات وبعض المواضيع المتقدمة فى مكتبة كايرو للرسم المتجهى. لمعظم الأمثلة سنستخدم مكتبة GTK+ ولغة السى
 +
 +
 +
 +
 +==== الرسم المتجهى ====
 +
 +
 +هنا نوعان من جرافيك الكمبيوتر **متجهى** و **raster**
 +ال Raster يمثل الصور على انها مجموعة من البكسلز بينما المتجهى يعتمد على اساسيات الأشكال من نقاط وخطوط ومنحنيات ليعبر عن الصور. ويتم عملها بناء على معادلات رياضية.
 +كلا النوعين لهما ميزات وعيوب.. من مميزات المتجهى على ال raster التالى:
 +
 +  * مساحة اصغر
 +  * امكانية التكبير -zoom- لانهائى
 +  * النقل والتوسيع والملأ او الدوران لا تقلل من جودة الصورة
 +
 +==== كايرو ====
 +
 +كايرو هى مكتبة للرسم المتجهى ثنائى الأبعاد. مكتوبة بلغة C ويمكن استخدامها عن طريق لغات اخرى مثل Python, Perl, C++, Java,..الخ وايضا متعددة المنصات، فتعمل على لينكس وبى اس دى وماك وغيرهم
 +
 +
 +تتدعم كايرو backends مختلفة مثلا
 +
 +  * X Window System
 +  * Win32 GDI
 +  * Mac OS X Quartz
 +  * PNG
 +  * PDF
 +  * PostScript
 +  * SVG
 +
 +
 +
 +مما يعنى اننا نستطيع ان نرسم على ويندوز، على لينكس او غيرهم ونستطيع استخدامها لعمل صور PNG وملفات PDF وملفات PostScript وايضا ملفات SVG
 +
 +نستطيع انا نقارن مكتبة كايرو بال **GDI** فى ويندوز او **Quartz 2D** فى ماك. كايرو مكتبة مفتوحة المصدر. ومنذ الإصدار 2.8 اصبحت جزء من **GTK+**
 +
 +==== ترجمة الأمثلة ====
 +
 +
 +الأمثلة مكتوبة بلغة C .فسنستخدم GCC لترجمتهم
 +
 +
 +
 +<code cpp>
 + gcc -o example `pkg-config --cflags --libs gtk+-2.0` example.c
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== تعريفات كايرو =====
 +
 +فى هذه الجزئية سنقدم بعض التعريفات المفيدة لفهم افضل مع نظام الرسم فى كايرو
 +
 +
 +
 +==== السياق ====
 +
 +لعمل بعض الرسم فى كايرو، يجب اولا انشاء سياق، ليحمل كل معاملات حالة الرسم. وهذا يشمل معلومات مثل سمك الخط واللون. 
 +السطح: هو المكان للرسم اليه وبعض الأشياء الأخرى. فهو يسمح لدوال الرسم الأصلية بأخذ معاملات اقل لتسهيل ال Interface مثلا **gdk_cairo_create()** تنشئ سياق للرسم الى المرسوم 
 +
 +
 +
 +To do some drawing in Cairo, we must first create a Cairo context. The Cairo context holds all of the graphics state parameters that describe how drawing is to be done. This includes information such as line width, color, the surface to draw to, and many other things. This allows the actual drawing functions to take fewer arguments to simplify the interface. The **gdk_cairo_create()** function call creates a cairo context for drawing to drawable. 
 +
 +
 +
 +
 +<code cpp>
 +  cairo_t *cr;
 +  cr = gdk_cairo_create(widget->window);
 +</code>
 +
 +
 +السطرين السابقين انشأو سياق. لاحظ ان السياق مرتبط ب **GdkDrawable** 
 +البناء cairo_t يشمل حالة المٌرندر واحداثيات الأشكال اللتى سترسم. الكائنات المنشئة من البناء cairo_t تدعى سياقات كايرو 
 +
 +
 +كل الرسم يتم دائما الى كائن cairo_t .السياق مرتبط بسطح ما، PDF, SVG, PNG, GtkDrawable .. الخ
 +
 +GDK لاتغلف Cairo. تسمح بإنشاء سياق ليستخدم فى الرسم على اى سطح قابل للرسم عليه. الدوال الإضافية تسمح بتحويل المستطيلات والمناطق الخاصة بGDK الى مسارات و pixbufs كمصدر لعملية الرسم
 +
 +
 +
 +==== المسار ====
 +
 +
 +المسار يتكون من خط او اكثر، كل من الخطوط مرتبط بنقطتين او اكتر.
 +المسارات ممكن ان تتكون من خطوط مستقيمة او منحنيات. 
 +هناك نوعين من المسارات: مفتوح ومغلق. فى المسار المغلق تلتقى نقطتى البداية والنهاية معا بعكس المسار المفتوح
 +
 +فى كايرو نبدأ بمسار خالى. اولا نقوم بتعريف المسار ثم نجعله ظاهرة بال stroking والملء. 
 +ملحوظة مهمة: بعد كل استدعاء ل **cairo_stroke()** او **cairo_fill()** يتم تفريغ المسار. فيجب علينا اعادة تعريف مسار جديد. 
 +المسار يتكون من عدة مسارات فرعية
 +
 +
 +
 +==== المصدر ====
 +
 +هو الدهان او الطلاء الذى سنستخدمه فى الرسم. نستطيع ان نشبه بالحبر. وسنستخدمه لعملية التحديد الخارجى وملء الأشكال.
 +هناك 4 انواع من المصادر: الألوان ، التدرجات ، الأنماط ، الصور
 +
 +
 +
 +
 +==== السطح ====
 +
 +
 +السطح هو الوجهة اللتى سنرسم اليها. نستطيع "رندرة" الوثائق بإستخدام اسطح PDF او PostScript مباشرة الى المنصة عبر اسطح Xlib او Win32
 +
 +
 +الوثائق ذكرت الأسطح التالية:
 +
 +
 +
 +
 +<code cpp>
 +typedef enum _cairo_surface_type {
 +  CAIRO_SURFACE_TYPE_IMAGE,
 +  CAIRO_SURFACE_TYPE_PDF,
 +  CAIRO_SURFACE_TYPE_PS,
 +  CAIRO_SURFACE_TYPE_XLIB,
 +  CAIRO_SURFACE_TYPE_XCB,
 +  CAIRO_SURFACE_TYPE_GLITZ,
 +  CAIRO_SURFACE_TYPE_QUARTZ,
 +  CAIRO_SURFACE_TYPE_WIN32,
 +  CAIRO_SURFACE_TYPE_BEOS,
 +  CAIRO_SURFACE_TYPE_DIRECTFB,
 +  CAIRO_SURFACE_TYPE_SVG,
 +  CAIRO_SURFACE_TYPE_OS2
 +} cairo_surface_type_t;
 +</code>
 +
 +==== القناع ====
 +
 +قبل ان يتم تطبيق المصدر على السطح يتم ترشيحه -فلترته- اولا. فيستخدم القناع كمرشح -فلتر-. يحدد اي الأماكن سيتم تطبيق المصدر 
 +
 +الأجزاء الغير شفافة فى القناع تتيح نسخ المصدر بعكس الأجزاء الشفافة
 +Before the source is applied to the surface, it is filtered first. The mask is used as a filter. The mask determines, 
 +where the sourse is applied and where not. Opaque parts of the mask allow to copy the source. Transparent parts do not
 +let to copy the source to the surface. 
 +
 +
 +
 +
 +
 +==== النمط ====
 +
 +النمط فى كايرو يعبر عن المصدر عند الرسم، فى كايرو: النمط هو شئ تستطيع ان تقرا منه يستخدم كمصدر او مرشح لعملية الرسم وقد يكون مصمت او متدرج او غيره
 +
 +
 +A cairo pattern represents a source when drawing onto a surface.
 +In cairo, a pattern is something that you can read from, that is used as the source or mask of a drawing operation. Patterns in cairo can be solid, surface-based, or even gradients patterns.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Cairo backends =====
 +
 +
 +
 +
 +
 +
 +The Cairo library supports various backends. In this section of the Cairo graphics tutorial, we will use
 +Cairo to create a PNG image, PDF file, SVG file and we will draw on a GTK window.
 +
 +
 +
 +
 +==== PNG image ====
 +
 +
 +
 +فى اول مثال سننشئ صورة PNG
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +
 +int main (int argc, char *argv[])
 +{
 +  cairo_surface_t *surface;
 +  cairo_t *cr;
 +
 +  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 390, 60);
 +  cr = cairo_create(surface);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_NORMAL);
 +  cairo_set_font_size(cr, 40.0);
 +
 +  cairo_move_to(cr, 10.0, 50.0);
 +  cairo_show_text(cr, "Disziplin ist Macht.");
 +
 +  cairo_surface_write_to_png(surface, "image.png");
 +
 +  cairo_destroy(cr);
 +  cairo_surface_destroy(surface);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +المثال تطبيق console لإنشاء صورة PNG
 +
 +
 +
 +<code cpp>
 + #include &lt;cairo.h&gt;
 +</code>
 +
 +
 +فى الملف الرأسى نجد التعريفات للدوال والثوابت الخاصة بنا.
 +
 +<code cpp>
 + cairo_surface_t *surface;
 + cairo_t *cr;
 +</code>
 +
 +
 +هنا نعرف السطح وسياق كايرو
 +
 +
 +<code cpp>
 + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 390, 60);
 + cr = cairo_create(surface);
 +</code>
 +
 +
 +
 +هنا انشئنا السطح والسياق. السطح 390*60 بكسل
 +
 +
 +
 +<code cpp>
 + cairo_set_source_rgb(cr, 0, 0, 0);
 +</code>
 +سنرسم بالحبر الإسود
 +
 +
 +
 +
 +<code cpp>
 + cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_NORMAL);
 + cairo_set_font_size(cr, 40.0);
 +</code>
 +
 +
 +نختار نوع الخط ونحدد الحجم 
 +
 +<code cpp>
 + cairo_move_to(cr, 10.0, 50.0);
 + cairo_show_text(cr, "Disziplin ist Macht.");
 +</code>
 +
 +ننتقل الى الموضع a (10.0, 50.0) فى الصورة ونرسم النص  
 +
 +
 +<code cpp>
 + cairo_surface_write_to_png(surface, "image.png");
 +</code>
 +
 +
 +
 +الدالة السابقة تنشئ صورة ال PNG
 +
 +
 +<code cpp>
 + cairo_destroy(cr);
 + cairo_surface_destroy(surface);
 +</code>
 +
 +
 +
 +فى النهاية نقوم بالتخلص من المصادر -عملية تنظيف للمصادر المستخدمة-
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/image.png |PNG image}}
 +
 +
 +
 +
 +
 +==== PDF file ====
 +
 +
 +فى المثال التالى، سنستخدم مكتبة Cairo لعمل ملف PDF بسيط
 +
 +
 +<code cpp>
 +#include &lt;cairo/cairo.h&gt;
 +#include &lt;cairo/cairo-pdf.h&gt;
 +
 +int main() {
 +
 +  cairo_surface_t *surface;
 +  cairo_t *cr;
 +
 +  surface = cairo_pdf_surface_create("pdffile.pdf", 504, 648);
 +  cr = cairo_create(surface);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_NORMAL);
 +  cairo_set_font_size (cr, 40.0);
 +
 +  cairo_move_to(cr, 10.0, 50.0);
 +  cairo_show_text(cr, "Disziplin ist Macht.");
 +
 +  cairo_show_page(cr);
 +
 +  cairo_surface_destroy(surface);
 +  cairo_destroy(cr);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +يجب فتح الملف فى عارض PDF .مستخدمى لينكس يستطيعو استخدام KPDF او Evnice 
 +
 +We must open the pdf file in a pdf viewer. Linux users can use KPDF or Evince viewers.
 +
 +
 +
 +
 +<code cpp>
 + surface = cairo_pdf_surface_create("pdffile.pdf", 504, 648);
 +</code>
 +
 +
 +ل"رندرة" ملف ال PDF يجب انشاء سطح PDF عن طريق الدالة **cairo_pdf_surface_create()** ثم تحديد المساحة بصورة نقط
 +
 +
 +
 +
 +<code cpp>
 + cairo_show_page(cr);
 +</code>
 +
 +الدالة **cairo_show_page()** تنهى ال "رندرة" لملف ال PDF
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/pdffile.png |PDF file in Evince}}
 +
 +
 +
 +
 +
 +==== SVG file ====
 +
 +فى المثال التالى سننشئ ملف SVG (Scalable Vector Graphics)  بسيط 
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;cairo-svg.h&gt; 
 + 
 +int main() {
 +
 +  cairo_surface_t *surface;
 +  cairo_t *cr;
 +
 +  surface = cairo_svg_surface_create("svgfile.svg", 390, 60);
 +  cr = cairo_create(surface);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_NORMAL);
 +  cairo_set_font_size (cr, 40.0);
 +
 +  cairo_move_to(cr, 10.0, 50.0);
 +  cairo_show_text(cr, "Disziplin ist Macht.");
 +
 +  cairo_surface_destroy(surface);
 +  cairo_destroy(cr);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +نستخدم فيرفكس ، اوبرا او انكسكيب لعرض ملفات ال svg 
 +
 +
 +
 +<code cpp>
 + surface = cairo_svg_surface_create("svgfile.svg", 390, 60);
 +</code>
 +
 +لإنشاء ملف SVG يجب اولا انشاء سطح SVG عن طريق **cairo_svg_surface_create()**
 +
 +
 +باقى الكود مشابة للسابق
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/svgfile.png |SVG file in Opera}}
 +
 +
 +
 +
 +
 +==== نافذة GTK ====
 +
 +فى المثال الأخير سنقوم بالرسم على نافذة GTK وسنقوم بإستخدامها على مدار باقى الدروس
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +static gboolean
 +on_expose_event(GtkWidget      *widget,
 + GdkEventExpose *event,
 + gpointer        data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_NORMAL);
 +  cairo_set_font_size(cr, 40.0);
 +
 +  cairo_move_to(cr, 10.0, 50.0);
 +  cairo_show_text(cr, "Disziplin ist Macht.");
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +     G_CALLBACK (on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +     G_CALLBACK (gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 400, 90); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +المثال يعرض نافذة فى منتصف الشاشة -متسنترة- نرسم عليها النص "Disziplin ist Macht"
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +</code>
 +
 +
 +
 +
 +We include the necessary Cairo and GTK headers.
 +
 +
 +
 +
 +<code cpp>
 + g_signal_connect(window, "expose-event",
 +     G_CALLBACK(on_expose_event), NULL);
 +</code>
 +
 +
 +عند اعادة رسم النافذة يتم بعث الإشارة **expose-event** فنقوم بربطها بمعالج الإشارة  **on_expose_event()**
 +
 +
 +تقوم اداة التطوير بإعادة رسم المناطق المكشوفة بالنسبة للنوافذ العادية فستقوم بتصفية -محو- الخلفية. واذا اردت ان تقوم برسوماتك الخاصة يجب ان تعلم GTK عن ذلك عن طريق الدالة **gtk_widget_set_app_paintable** 
 +
 +<code cpp>
 + gtk_widget_set_app_paintable(window, TRUE)
 +</code>
 +
 +
 +اذا اردت الرسم فى GTK+ فيمكننا الرسم على ويدجت **GtkDrawingArea**  او على **GtkWindow** بسيطة. انا اخترت الأخير.
 +للرسم على  النافذة لابد ان نبلغ GTK+ عبر استدعاء **gtk_widget_set_app_paintable** فتقوم هذه الدالة بكتم -اخفاء- او كبح الرسم الإفتراضى فى خلفية الويدجت. فى حال استخدام **GtkDrawingArea** فإننا لانحتاج لإستدعاء هذه الدالة.
 +
 +
 +<code cpp>
 + cairo_t *cr;
 +
 + cr = gdk_cairo_create(widget->window);
 +</code>
 +
 +
 +يتم الرسم فى معالج الإشارة **on_expose_event** ، فيه نقوم بإنشاء سياق كايرو ونرسم النص كالمعتاد.
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/gtkwindow.png |GTK window}}
 +
 +===== اساسيات الرسم فى كايرو =====
 +
 +فى هذه الجزئية، سنقوم برسم بعض الأساسيات مثل الخطوط سنقوم بعمليتى الملء والتحديد وسنتكلم عن الداشات -dashes- وربط الخطوط
 +
 +
 +==== الخطوط ====
 +
 +الخطوط هى كائنات اساسية فى المتجهات. لرسم سطر نستدعى دالتين.لتحديد نقطة البداية ب **cairo_move_to()** بينما نقطة النهاية تحدد ب **cairo_line_to()**
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +double coordx[100];
 +double coordy[100];
 +
 +int count = 0;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_set_line_width (cr, 0.5);
 +
 +  int i, j;
 +  for ( i = 0; i <= count - 1; i++ ) {
 +      for ( j  = 0; j <= count -1; j++ ) {
 +          cairo_move_to(cr, coordx[i], coordy[i]);
 +          cairo_line_to(cr, coordx[j], coordy[j]);
 +      }
 +  }
 +
 +  count = 0;
 +  cairo_stroke(cr);
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +gboolean clicked(GtkWidget *widget, GdkEventButton *event,
 +    gpointer user_data)
 +{
 +    if (event->button == 1) {
 +        coordx[count] = event->x;
 +        coordy[count++] = event->y;
 +    }
 +
 +    if (event->button == 3) {
 +        gtk_widget_queue_draw(widget);
 +    }
 +
 +    return TRUE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +  
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 + 
 +  gtk_widget_add_events (window, GDK_BUTTON_PRESS_MASK);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +  g_signal_connect(window, "button-press-event", 
 +      G_CALLBACK(clicked), NULL);
 + 
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_title(GTK_WINDOW(window), "lines");
 +  gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +فى المثال، نضغط عشوائيا على النافذة بالزر الأيسر للفأرة، يتم تخزين كل ضغطه فى مصفوفة وعندما نضغط بالزر الأيمن يتم دمج جميع النقاط فى المصفوفة. بهذه الطريقة نستطيع عمل كائنات مثيرة للإهتمام. الضغط بالزر الأيمن يقوم بتصفية -تنظيف- النافذة ، ونستطيع الضغط لكائن اخر 
 +
 +
 +<code cpp>
 + cairo_set_source_rgb(cr, 0, 0, 0);
 + cairo_set_line_width (cr, 0.5);
 +</code>
 +
 +
 +
 +هذه السطور سترسم بالحبر الإسود مع سمك 0.5 
 +
 +
 +
 +
 +
 +<code cpp>
 + int i, j;
 + for ( i = 0; i <= count - 1; i++ ) {
 +     for ( j  = 0; j <= count -1; j++ ) {
 +         cairo_move_to(cr, coordx[i], coordy[i]);
 +         cairo_line_to(cr, coordx[j], coordy[j]);
 +     }
 + }
 +</code>
 +
 +
 +نربط كل النقاط مع النقط الأخرى
 +
 +
 +
 +
 +
 +<code cpp>
 + cairo_stroke(cr);
 +</code>
 +الدالة **cairo_stroke()** تقوم برسم الخطوط
 +
 +
 +
 +<code cpp>
 + g_signal_connect(window, "button-press-event", 
 +     G_CALLBACK(clicked), NULL);
 +</code>
 +
 +
 +نربط **button-press-event** بالمعالج clicked
 +
 +We connect the **button-press-event** to the clicked callback.  
 +
 +
 +<code cpp>
 + if (event->button == 1) {
 +     coordx[count] = event->x;
 +     coordy[count++] = event->y;
 + }
 +</code>
 +
 +
 +داخل المعالج clicked نقوم بتحديد هل كانت الضغطة على الفأرة بالزر الأيمن او الأيسر، إذا كان الأيسر نقوم بتخزين احداثيات x,y 
 +
 +
 +<code cpp>
 + if (event->button == 3) {
 +     gtk_widget_queue_draw(widget);
 + }
 +</code>
 +
 +
 +بالضغط على الزر الأيمن نعيد رسم النافذة
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/lines.png |Lines}}
 +
 +
 +==== الملء والتحديد ====
 +
 +عملية ال stroke تقوم برسم الحدود الخارجية للشكل
 +عملية ال fill تقوم بملء ماداخل الشكل
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;math.h&gt;
 +
 +static gboolean
 +on_expose_event (GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  int width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
 +  cairo_set_line_width(cr, 9);
 +
 +  cairo_set_source_rgb(cr, 0.69, 0.19, 0);
 +  cairo_arc(cr, width/2, height/2, 
 +      (width < height ? width : height) / 2 - 10, 0, 2 * M_PI);
 +  cairo_stroke_preserve(cr);
 +
 +  cairo_set_source_rgb(cr, 0.3, 0.4, 0.6); 
 +  cairo_fill(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 200, 150); 
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +فى المثال سنقوم برسم دائرة 
 +
 +
 +<code cpp>
 + #include &lt;math.h&gt;
 +</code>
 +
 +
 +نحتاج هذا الملف الرأسى للثابت **M_PI**
 +
 +
 +<code cpp>
 + int width, height;
 + gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
 +</code>
 +
 +
 +نحصل على عرض وارتفاع النافذة، نحتاج هذه القيم ليتم اعادة تحجيم الدائرة عند اعادة تحجيم النافذة
 +
 +
 +<code cpp>
 + cairo_set_source_rgb(cr, 0.69, 0.19, 0);
 + cairo_arc(cr, width/2, height/2, 
 +     (width < height ? width : height) / 2 - 10, 0, 2 * M_PI);
 + cairo_stroke_preserve(cr);
 +</code>
 +
 +نرسم الحدود الخارجية للدائرة
 +
 +
 +<code cpp>
 + cairo_set_source_rgb(cr, 0.3, 0.4, 0.6); 
 + cairo_fill(cr);
 +</code>
 +
 +
 +
 +نملئها بلون ازرق
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/fillstroke.png |Fill and stroke}}
 +
 +
 +<!--<code cpp>
 +
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +-->
 +
 +==== Dash ====
 +
 +كل سطر يمكن ان يرسم ب داش مختلف. مما يحدد ستايل الخط. يستخدم الداش فى الدالة  **cairo_stroke()**
 +
 +نمط الداش يتم تحديده بالدالة **cairo_set_dash()** .ويتم تحديده من خلال مصفوفة الداش -مصفوفة من القيم الموجبة لتحديد الأماكن اللتى سيتم فيها رسم الخط داخل السطر. ايضا نقوم بتحديد طول المصفوفة وال offset . فى حال كان الطول للمصفوفة 0 يتم الغاء الداشينج. واذا كانت 1 يعتبر متماثل. ويحدد ال offset قيمة البداية -او بكلمات اخرى المساحة الفارغة عند البداية
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_rgba(cr, 0, 0, 0, 1);
 +
 +  static const double dashed1[] = {4.0, 1.0};
 +  static int len1  = sizeof(dashed1) / sizeof(dashed1[0]);
 +
 +  static const double dashed2[] = {4.0, 1.0, 4.0};
 +  static int len2  = sizeof(dashed2) / sizeof(dashed2[0]);
 +
 +  static const double dashed3[] = {1.0};
 +
 +  cairo_set_line_width(cr, 1.5);
 +
 +  cairo_set_dash(cr, dashed1, len1, 0);
 +
 +  cairo_move_to(cr, 40, 30);  
 +  cairo_line_to(cr, 200, 30);
 +  cairo_stroke(cr);
 +
 +  cairo_set_dash(cr, dashed2, len2, 1);
 +
 +  cairo_move_to(cr, 40, 50);  
 +  cairo_line_to(cr, 200, 50);
 +  cairo_stroke(cr);
 +
 +  cairo_set_dash(cr, dashed3, 1, 0);
 +
 +  cairo_move_to(cr, 40, 70);  
 +  cairo_line_to(cr, 200, 70);
 +  cairo_stroke(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +  GtkWidget *darea;  
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  darea = gtk_drawing_area_new();
 +  gtk_container_add(GTK_CONTAINER(window), darea);
 +
 +  g_signal_connect(darea, "expose-event",
 +      G_CALLBACK (on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK (gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 250, 100); 
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى المثال، سنرسم 3 خطوط مع انماط داش مختلفة
 +
 +
 +<code cpp>
 + static const double dashed1[] = {4.0, 1.0};
 +</code>
 +
 +
 +هنا نحدد اول نمط. سنرسم نمط من 4 بكسل ونقطة فارغة
 +
 +
 +<code cpp>
 + static int len1  = sizeof(dashed1) / sizeof(dashed1[0]);
 +</code>
 +
 +
 +نحصل على حجم ال array
 +
 +
 +
 +
 +<code cpp>
 + cairo_set_dash(cr, dashed1, len1, 0);
 +</code>
 +
 +
 +
 +
 +نحدد الداش
 +
 +
 +
 +<code cpp>
 + darea = gtk_drawing_area_new();
 + gtk_container_add(GTK_CONTAINER(window), darea);
 +</code>
 +
 +
 +فى المثال لانقوم بالرسم مباشرة ولكن عبر ال drawing area
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/dashes.png |Dashes}}
 +
 +
 +
 +==== Line caps ====
 +
 +ال Line caps هى نقط النهاية للخط
 +
 +
 +   * CAIRO_LINE_CAP_SQUARE 
 +   * CAIRO_LINE_CAP_ROUND
 +   * CAIRO_LINE_CAP_BUTT
 +
 +
 +
 +هناك 3 انواع مختلفة فى كايرو
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/linecaps.png |Line caps}}
 +
 +الخط ب **CAIRO_LINE_CAP_SQUARE** سيكون لديه حجم مختلف عن خط ب **CAIRO_LINE_CAP_BUTT**
 +لو كان خط بعرض 1 بكسل فسيكون الخط ب **CAIRO_LINE_CAP_SQUARE**  سيكون نفس العرض بكسل زيادة فى الحجم. العرض/2 بكسل فى البداية و العرض/2 بكسل فى النهاية 
 +##FIXME
 +
 +A line with a **CAIRO_LINE_CAP_SQUARE** cap will have a different size, than a line with a 
 +**CAIRO_LINE_CAP_BUTT** cap. If a line is width px wide, the line with a **CAIRO_LINE_CAP_SQUARE** cap will be exactly width px greater in size. width/2 px at the beginning and width/2 px at the end.
 +
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_rgba(cr, 0, 0, 0, 1);
 +  cairo_set_line_width(cr, 10);
 +
 +  cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); 
 +  cairo_move_to(cr, 30, 50); 
 +  cairo_line_to(cr, 150, 50);
 +  cairo_stroke(cr);
 +
 +  cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); 
 +  cairo_move_to(cr, 30, 90); 
 +  cairo_line_to(cr, 150, 90);
 +  cairo_stroke(cr);
 +
 +  cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); 
 +  cairo_move_to(cr, 30, 130); 
 +  cairo_line_to(cr, 150, 130);
 +  cairo_stroke(cr);
 +
 +  cairo_set_line_width(cr, 1.5);
 +
 +  cairo_move_to(cr, 30, 40);  
 +  cairo_line_to(cr, 30, 140);
 +  cairo_stroke(cr);
 +
 +  cairo_move_to(cr, 150, 40);  
 +  cairo_line_to(cr, 150, 140);
 +  cairo_stroke(cr);
 +
 +  cairo_move_to(cr, 155, 40);  
 +  cairo_line_to(cr, 155, 140);
 +  cairo_stroke(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +  GtkWidget *darea;  
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  darea = gtk_drawing_area_new ();
 +  gtk_container_add(GTK_CONTAINER (window), darea);
 +
 +  g_signal_connect(darea, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 200, 200); 
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +فى المثال نرسم 3 خطوط ب 3 caps مختلفة. سيعرضلنا ايضا الإختلاف فى المساحة للخطوط
 +The example draws three lines with three different caps. It will also graphically demonstrate the differences is size of the lines.
 +
 +
 +
 +
 +<code cpp>
 + cairo_set_line_width(cr, 10);
 +</code>
 +
 +
 +خطوطنا ستكون بعرض 10 بكسل
 +
 +
 +
 +
 +<code cpp>
 + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); 
 + cairo_move_to(cr, 30, 90); 
 + cairo_line_to(cr, 150, 90);
 + cairo_stroke(cr);
 +</code>
 +
 +هنا نرسم خط افقى ب **CAIRO_LINE_CAP_ROUND**
 +
 +
 +
 +<code cpp>
 + cairo_set_line_width(cr, 1.5);
 +
 + cairo_move_to(cr, 30, 40);  
 + cairo_line_to(cr, 30, 140);
 + cairo_stroke(cr);
 +</code>
 +
 +
 +
 +هذا الخط من ال 3 خطوط الرأسية يستخدم لعرض الفرق فى المساحة
 +This is one of the three vertical lines used to demostrate the differences in size.
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/caps.png |Line caps}}
 +
 +
 +==== رابطات الخطوط ====
 +
 +نستطيع ربط الخطوط ب3 ستايلات 
 +
 +
 +   * CAIRO_LINE_JOIN_MITER 
 +   * CAIRO_LINE_JOIN_BEVEL
 +   * CAIRO_LINE_JOIN_ROUND
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/joins.jpg |Bevel, Round, Miter line joins}}
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_rgb(cr, 0.1, 0, 0);
 +
 +  cairo_rectangle(cr, 30, 30, 100, 100);
 +  cairo_set_line_width(cr, 14);
 +  cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); 
 +  cairo_stroke(cr);
 +
 +  cairo_rectangle(cr, 160, 30, 100, 100);
 +  cairo_set_line_width(cr, 14);
 +  cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); 
 +  cairo_stroke(cr);
 +
 +  cairo_rectangle(cr, 100, 160, 100, 100);
 +  cairo_set_line_width(cr, 14);
 +  cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); 
 +  cairo_stroke(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +  GtkWidget *darea;  
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  darea = gtk_drawing_area_new();
 +  gtk_container_add(GTK_CONTAINER(window), darea);
 +
 +  g_signal_connect(darea, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 + 
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 300, 280); 
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +
 +}
 +</code>
 +
 +
 +فى المثال نرسم 3 مستطيلات سميكة مع رابطات خطوط متنوعة. 
 +
 +
 +
 +
 +<code cpp>
 + cairo_rectangle(cr, 30, 30, 100, 100);
 + cairo_set_line_width(cr, 14);
 + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); 
 + cairo_stroke(cr);
 +</code>
 +
 +
 +
 +فى هذا الكود، رسمنا مستطيل برابط **CAIRO_LINE_JOIN_MITER**  والخطوط عرضها 14 بكسل
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/linejoins.png |Line joins}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== الأشكال والملء فى كايرو =====
 +
 +
 +فى هذه الجزئية سننشئ بعض الأشكال البسيطة والمتقدمة وسنملئهم بصورة بألوان مصمته، وانماط،وتدرجات
 +
 +
 +
 +==== الأشكال الأساسية ====
 +
 +تقدم لنا كايرو العديد من الدوال لإنشاء الأشكال الأساسية.
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;math.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_set_line_width(cr, 1);
 +
 +  cairo_rectangle(cr, 20, 20, 120, 80);
 +  cairo_rectangle(cr, 180, 20, 80, 80);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_arc(cr, 330, 60, 40, 0, 2*M_PI);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_arc(cr, 90, 160, 40, M_PI/4, M_PI);
 +  cairo_close_path(cr);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_translate(cr, 220, 180);
 +  cairo_scale(cr, 1, 0.7);
 +  cairo_arc(cr, 0, 0, 50, 0, 2*M_PI);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +  GtkWidget *darea;  
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  darea = gtk_drawing_area_new();
 +  gtk_container_add(GTK_CONTAINER (window), darea);
 +
 +  g_signal_connect(darea, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 390, 240); 
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى المثال نرسم مستطيل، مربع، دائرة، قوس و قطع ناقص
 +
 +
 +<code cpp>
 + cairo_rectangle(cr, 20, 20, 120, 80);
 + cairo_rectangle(cr, 180, 20, 80, 80);
 +</code>
 +
 +الدالة **cairo_rectangle()** تستخدم لعمل مربعات ومستطيلات
 +-المربع هو نوع خاص من المستطيلات فيه الطول=العرض-
 +
 +
 +<code cpp>
 + cairo_arc(cr, 330, 60, 40, 0, 2*M_PI);
 +</code>
 +
 +هذا السطر ينشئ الدائرة
 +
 +
 +<code cpp>
 + cairo_scale(cr, 1, 0.7);
 + cairo_arc(cr, 0, 0, 50, 0, 2*M_PI);
 +</code>
 +
 +نستخدم **cairo_scale()** لإنشاء القطع الناقص
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/shapes.png |Shapes}}
 +الأشكال الأخرى -المعقد منها خصوصا- نستطيع انشاءها بتجميع الأساسيات
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +int points[11][2] = { 
 +    { 0, 85 }, 
 +    { 75, 75 }, 
 +    { 100, 10 }, 
 +    { 125, 75 }, 
 +    { 200, 85 },
 +    { 150, 125 }, 
 +    { 160, 190 },
 +    { 100, 150 }, 
 +    { 40, 190 },
 +    { 50, 125 },
 +    { 0, 85 } 
 +};
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_set_line_width(cr, 1);
 +
 +
 +  gint i;
 +  for ( i = 0; i < 10; i++ ) {
 +      cairo_line_to(cr, points[i][0], points[i][1]);
 +  }
 +
 +  cairo_close_path(cr);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +
 +  cairo_move_to(cr, 240, 40);
 +  cairo_line_to(cr, 240, 160);
 +  cairo_line_to(cr, 350, 160);
 +  cairo_close_path(cr);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_move_to(cr, 380, 40);
 +  cairo_line_to(cr, 380, 160);
 +  cairo_line_to(cr, 450, 160);
 +  cairo_curve_to(cr, 440, 155, 380, 145, 380, 40);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +  GtkWidget *darea;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  darea = gtk_drawing_area_new();
 +  gtk_container_add(GTK_CONTAINER (window), darea);
 +
 +  g_signal_connect(darea, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 460, 240); 
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى هذا المثال ننشئ نجمة، مثلث -هذه الأشكال تنشئ عن طريق الخطوط ومنحنى
 +
 +
 +<code cpp>
 + gint i;
 + for ( i = 0; i < 10; i++ ) {
 +     cairo_line_to(cr, points[i][0], points[i][1]);
 + }
 +
 + cairo_close_path(cr);
 +</code>
 +
 +
 + ‪ النجمة ترسم عن طريق جمع كل النقاط -الموجودة فى مصفوفة النقط-ويتم انهاء النجمة بإستدعاء **cairo_close_path()**  التى تقوم بربط اخر نقطتين 
 +  ‬ 
 +<code cpp>
 + cairo_move_to(cr, 380, 40);
 + cairo_line_to(cr, 380, 160);
 + cairo_line_to(cr, 450, 160);
 + cairo_curve_to(cr, 440, 155, 380, 145, 380, 40);
 +</code>
 +
 +
 +المستطيل المعدل هو عبارة عن دمج لخطين ومنحنى.
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/shapes2.png |Shapes}}
 +
 +
 +
 +
 +==== Fills ====
 +
 +
 +
 +المالئات ؟ 
 +#FIXME : مش الأصل fillers ?
 +
 +
 +Fills fill the interiors of shapes. Fills can be solid colors, patters or gradients.
 +
 +
 +
 +
 +
 +
 +=== Solid colors ===
 +
 +
 +اللون هو كائن يمثل تجميعة من الأحمر والأخضر والأزرق RGB القيم المسموحة بين الفترة 0 و 1
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  int width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height);  
 +
 +
 +  cairo_set_source_rgb(cr, 0.5, 0.5, 1);
 +  cairo_rectangle(cr, 20, 20, 100, 100);
 +  cairo_fill(cr);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 150, 20, 100, 100);
 +  cairo_fill(cr);
 + 
 +  cairo_set_source_rgb(cr, 0, 0.3, 0);
 +  cairo_rectangle(cr, 20, 140, 100, 100);
 +  cairo_fill(cr);
 +
 +  cairo_set_source_rgb(cr, 1, 0, 0.5);
 +  cairo_rectangle(cr, 150, 140, 100, 100);
 +  cairo_fill(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 270, 260); 
 +  gtk_window_set_title(GTK_WINDOW(window), "colors");
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main(); 
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى المثال نرسم 4 مستطيلات ملونة.
 +
 +
 +
 +<code cpp>
 + cairo_set_source_rgb(cr, 0.5, 0.5, 1);
 + cairo_rectangle(cr, 20, 20, 100, 100);
 + cairo_fill(cr);
 +</code>
 +
 +الدالة **cairo_set_source_rgb** تقوم بتحديد المصدر الى لون غير شفاف ومعاملاتها هى قيم الأحمر والأخضر والأزرق.
 +المصدر سيستخدم لملء داخل المستطيل ويتم ذلك عن طريق الدالة **cairo_fill**
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/colors.png |Solid colors}}
 +
 +
 +=== الأنماط ===
 +
 +
 +الأنماط هى كائنات رسومية معقدة يمكن ان تملء الأشكال.
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +cairo_surface_t *surface1;
 +cairo_surface_t *surface2;
 +cairo_surface_t *surface3;
 +cairo_surface_t *surface4;
 +
 +static void create_surfaces() {
 +  surface1 = cairo_image_surface_create_from_png("blueweb.png");
 +  surface2 = cairo_image_surface_create_from_png("maple.png");
 +  surface3 = cairo_image_surface_create_from_png("crack.png");
 +  surface4 = cairo_image_surface_create_from_png("chocolate.png");
 +}
 +
 +static void destroy_surfaces() {
 +  g_print("destroying surfaces");
 +  cairo_surface_destroy(surface1);
 +  cairo_surface_destroy(surface2);
 +  cairo_surface_destroy(surface3);
 +  cairo_surface_destroy(surface4);
 +}
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cairo_pattern_t *pattern1;
 +  cairo_pattern_t *pattern2;
 +  cairo_pattern_t *pattern3;
 +  cairo_pattern_t *pattern4;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  int width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height);  
 +
 +
 +  pattern1 = cairo_pattern_create_for_surface(surface1);
 +  pattern2 = cairo_pattern_create_for_surface(surface2);
 +  pattern3 = cairo_pattern_create_for_surface(surface3);
 +  pattern4 = cairo_pattern_create_for_surface(surface4);
 +
 +
 +  cairo_set_source(cr, pattern1);
 +  cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
 +  cairo_rectangle(cr, 20, 20, 100, 100);
 +  cairo_fill(cr);
 +
 +  cairo_set_source(cr, pattern2); 
 +  cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); 
 +  cairo_rectangle(cr, 150, 20, 100, 100);
 +  cairo_fill(cr);
 +
 +  cairo_set_source(cr, pattern3);
 +  cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
 +  cairo_rectangle(cr, 20, 140, 100, 100);
 +  cairo_fill(cr);
 +
 +  cairo_set_source(cr, pattern4);
 +  cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
 +  cairo_rectangle(cr, 150, 140, 100, 100);
 +  cairo_fill(cr);
 +
 +  cairo_pattern_destroy(pattern1);
 +  cairo_pattern_destroy(pattern2);
 +  cairo_pattern_destroy(pattern3);
 +  cairo_pattern_destroy(pattern4);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  create_surfaces();
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 270, 260); 
 +  gtk_window_set_title(GTK_WINDOW(window), "patterns");
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  destroy_surfaces();
 +
 +  return 0;
 +}
 +
 +</code>
 +
 +فى هذا المثال نرسم 4 مستطيلات مرة اخرى، ولكن هذه المرة نملئهم بإستخدام الأنماط -patterns-. نستخدم 4 انماط من برنامج **Gimp** لمعالجة الصور.
 +يجب ان نحتفظ بالحجم الأساسى للأنماط.. لأننا سوف ن tile هم ؟
 +FIXME: هل تترجم على اننا سوف نبلطهم ؟ 
 +
 +ننشئ الأسطح خارج الدالة **on_expose_event** لأنا لانريد قرائتها من القرص الصلب كل مرة تريد فيها النافذة اعادة رسم نفسها.
 +
 +
 +<code cpp>
 + pattern1 = cairo_pattern_create_for_surface(surface1);
 +</code>
 +
 +
 +
 +
 +We create a pattern from the surface by calling the **cairo_pattern_create_for_surface()** function.
 +
 +
 +
 +
 +<code cpp>
 +  cairo_set_source(cr, pattern1);
 +  cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
 +  cairo_rectangle(cr, 20, 20, 100, 100);
 +  cairo_fill(cr);
 +</code>
 +
 +**cairo_set_source** تخبر سياق كايرو ان تستخدم نمط كمصدر للرسم، ربما لاتتناسب الأنماط مع الشكل لذا نقوم بتحديدال mode الى **CAIRO_EXTEND_REPEAT** مما يقوم بتكرير النمط!
 +الدالة **cairo_rectangle** تنشئ مسار مستطيلى، واخيرا **cairo_fill** تملء ذلك المسار بالمصدر 
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/patterns.png |Patterns}}
 +
 +
 +
 +=== Gradients ===
 +
 +#FIXME: التعبير المناسب لل Gradient ؟
 +
 +
 +In computer graphics, gradient is a smooth blending of shades from light to dark or from one color to another. In 2D drawing programs and paint programs, gradients are used to create colorful backgrounds and special effects as well as to simulate lights and shadows. (answers.com)
 +
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cairo_pattern_t *pat1;
 +  cairo_pattern_t *pat2;
 +  cairo_pattern_t *pat3;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  pat1 = cairo_pattern_create_linear(0.0, 0.0,  350.0, 350.0);
 +
 +  gdouble j;
 +  gint count = 1;
 +  for ( j = 0.1; j < 1; j += 0.1 ) {
 +      if (( count % 2 ))  {
 +          cairo_pattern_add_color_stop_rgb(pat1, j, 0, 0, 0);
 +      } else { 
 +          cairo_pattern_add_color_stop_rgb(pat1, j, 1, 0, 0);
 +      }
 +   count++;
 +  }
 +
 +  cairo_rectangle(cr, 20, 20, 300, 100);
 +  cairo_set_source(cr, pat1);
 +  cairo_fill(cr);
 +
 +
 +  pat2 = cairo_pattern_create_linear(0.0, 0.0,  350.0, 0.0);
 +
 +  gdouble i;
 +  count = 1;
 +  for ( i = 0.05; i < 0.95; i += 0.025 ) {
 +      if (( count % 2 ))  {
 +          cairo_pattern_add_color_stop_rgb(pat2, i, 0, 0, 0);
 +      } else { 
 +          cairo_pattern_add_color_stop_rgb(pat2, i, 0, 0, 1);
 +      }
 +   count++;
 +  }
 +
 +  cairo_rectangle(cr, 20, 140, 300, 100);
 +  cairo_set_source(cr, pat2);
 +  cairo_fill(cr);
 +
 +
 +  pat3 = cairo_pattern_create_linear(20.0, 260.0, 20.0, 360.0);
 +
 +  cairo_pattern_add_color_stop_rgb(pat3, 0.1, 0, 0, 0);
 +  cairo_pattern_add_color_stop_rgb(pat3, 0.5, 1, 1, 0);
 +  cairo_pattern_add_color_stop_rgb(pat3, 0.9, 0, 0, 0);
 +
 +  cairo_rectangle(cr, 20, 260, 300, 100);
 +  cairo_set_source(cr, pat3);
 +  cairo_fill(cr);
 +
 +  cairo_pattern_destroy(pat1);
 +  cairo_pattern_destroy(pat2);
 +  cairo_pattern_destroy(pat3);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 340, 390); 
 +  gtk_window_set_title(GTK_WINDOW(window), "gradients");
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +نقوم فى المثال برسم 3 مستطيلات ب 3 (تدرجات؟) مختلفة
 +In our example, we draw three rectangles with three different gradients.
 +
 +
 +
 +
 +<code cpp>
 + pat3 = cairo_pattern_create_linear(20.0, 260.0, 20.0, 360.0);
 +</code>
 +
 +
 +هنا ننشئ نمط لجرادينت خطى.. والمعاملات هى السطر اللذى عليه نرسم الجرادينت.. فى حالتنا هنا هو خط رأسى
 +
 +
 +
 +<code cpp>
 + cairo_pattern_add_color_stop_rgb(pat3, 0.1, 0, 0, 0);
 + cairo_pattern_add_color_stop_rgb(pat3, 0.5, 1, 1, 0);
 + cairo_pattern_add_color_stop_rgb(pat3, 0.9, 0, 0, 0);
 +</code>
 +
 +
 +نحدد موقفات للون لإنشاء نمط الجرادينت وهنا يجمع بين الأسود والأصفر.. وبإضافة لونين اسود وتوقف اصفر ننشئ نمط جرادينت افقى.. ماذا تعنى تلك التوقفات حقيقة ؟فى حالتنا هذه نبدأ باللون الأسود اللذى يتوقف عند عشر مساحته ثم يبدأ برسم الأصفر تصاعديا التى ستتوج مركز الشكل.. ويتوقف الأصفر عند 9 من 10 المساحة حيث نعود نرسم الأسود مجددا وهكذا
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/gradients.png |Gradients}}
 +
 +===== الشفافية =====
 +
 +فى هذه الجزئية سنتخدث عن الشفافية وبعض التعريفات الأساسية وتأثيرين مثيرين للإهتمام 
 +
 +الشفافية هى الجودة للقدرة على الرؤية عبر المادة. 
 +ابسط طريقة لفهمها هى تخيل قطع من الزجاج او الماء، تقنيا اشعة الضوء تعبر سطح الزجاج او الماء لذا نستطيع ان نرى الأشياء خلفها
 +فى الحاسب، نستطيع الوصول لتأثيرات الشفافية عن طريق **alpha compositing**.
 +
 +**alpha compositing** هى عملية لدمج صورة مع خلفية لجعل المظهر شفاف جزئيا. عملية ال composition تستخدم **alpha channel**.
 +
 +alpha channel هى طبقة من 8 بت فى ملف جرافيك تستخدم للتعبير عن الشفافية. ال8 بت الإضافية لكل بكسل تعمل كقناع تعبر عن 256 مستوى للشفافية
 +
 +In computer graphics, we can achieve transparency effects using 
 +Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. 
 +
 +The composition process uses an **alpha channel**.
 +Alpha channel is an 8-bit layer in a graphics file format that is used for expressing translucency (transparency). The extra eight bits per pixel serves as a mask and represents 256 levels of translucency. 
 +
 +
 +(answers.com, wikipedia.org)
 +
 +
 +
 +
 +
 +
 +==== المستطيلات الشفافة ====
 +
 +فى المثال سنرسم 10 مستطيلات ذات مستويات مختلفة من الشفافية
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  gint i;
 +  for ( i = 1; i <= 10; i++) {
 +      cairo_set_source_rgba(cr, 0, 0, 1, i*0.1);
 +      cairo_rectangle(cr, 50*i, 20, 40, 40);
 +      cairo_fill(cr);  
 +  }
 +
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 590, 90); 
 +  gtk_window_set_title(GTK_WINDOW(window), "transparency");
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +**cairo_set_source_rgba()** لديها معامل اختيارى لقيمة الألفا للشفافية
 +
 +
 +
 +<code cpp>
 + gint i;
 + for ( i = 1; i <= 10; i++) {
 +     cairo_set_source_rgba(cr, 0, 0, 1, i*0.1);
 +     cairo_rectangle(cr, 50*i, 20, 40, 40);
 +     cairo_fill(cr);  
 + }
 +</code>
 +
 +هذا الكود ينشئ 10 مستطيلات ب قيم الفا تتدرج من 0.1 الى 1
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/transparency.png |Transparency}}
 +
 +
 +
 +==== تأثير التلاشى ====
 +
 +
 +فى المثال سنقوم بملاشاة صورة، ستزداد شفافيتها حتى تصبح مخفية تماما
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +cairo_surface_t *image;
 +gboolean timer = TRUE;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  static double alpha = 1;
 +  double const delta = 0.01;
 +
 +  cairo_set_source_surface(cr, image, 10, 10);
 +  cairo_paint_with_alpha(cr, alpha);
 +
 +  alpha -= delta; 
 +
 +  if (alpha <= 0) timer = FALSE;
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +
 +  if (!timer) return FALSE;
 +
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +  GtkWidget *darea;
 +
 +  gint width, height;
 +
 +  image = cairo_image_surface_create_from_png("turnacastle.png");
 +  width = cairo_image_surface_get_width(image);
 +  height = cairo_image_surface_get_height(image);
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  darea = gtk_drawing_area_new();
 +  gtk_container_add(GTK_CONTAINER (window), darea);
 +
 +  g_signal_connect(darea, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), width+20, height+20);
 +
 +  gtk_window_set_title(GTK_WINDOW(window), "fade out");
 +  g_timeout_add(50, (GSourceFunc) time_handler, (gpointer) window);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  cairo_surface_destroy(image);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +فى المثال سنقوم بملاشاة صورة، ستزداد شفافيتها حتى تصبح مخفية تماما
 +استخدمنا صورة بقايا قلعة Turna فى شرق سلوفاكيا تستطيع تحميلها <a href="../images/turnacastle.png">هنا</a>.
 +
 +
 +<code cpp>
 + image = cairo_image_surface_create_from_png("turnacastle.png");
 +</code>
 +
 +
 +لأسباب خاصة بالكفاءة، انشاء سطح الصورة نجعله فى الدالة main
 +
 +
 +<code cpp>
 + cairo_set_source_surface(cr, image, 10, 10);
 +</code>
 +
 +هنا نحدد المصدر
 +
 +
 +
 +
 +<code cpp>
 + cairo_paint_with_alpha(cr, alpha);
 +</code>
 +
 +تأثير التلاشى ينشئ بإستخدام الدالة **cairo_paint_with_alpha()** تلك الدالة تستخدم الشفافية كقناع
 +
 +
 +<code cpp>
 + alpha -= delta;
 +</code>
 +
 +هنا قللنا قيمة الفا كل مرة يتم فيها تنفيذ **on_expose_event()** 
 +
 +<code cpp>
 + if (alpha <= 0) timer = FALSE;
 +</code>
 +
 +
 +اذا كانت قيمة الفا اقل من او تساوى 0 ننهى تأثير التلاشى -بجعل قيمة المؤقت الى FALSE -لاننا لانحتاجه بعد ذلك--
 +
 +
 +<code cpp>
 + g_timeout_add(50, (GSourceFunc) time_handler, (gpointer) window);
 +</code>
 +
 +
 +ننشئ دالة مؤقت تستدعى **time_handler** كل 50 ms
 +
 +We create a timer function. This function will call **time_handler** every 50 ms. 
 +
 +
 +
 +
 +<code cpp>
 + static gboolean
 + time_handler (GtkWidget *widget)
 + {
 +   if (widget->window == NULL) return FALSE;
 +
 +   if (!timer) return FALSE;
 +
 +   gtk_widget_queue_draw(widget);
 +   return TRUE;
 + }
 +</code>
 +
 +
 +الهدف الأساسى ل **time_handler** لإعادة رسم النافذة بصورة منتظمة حتى تصبح قيمته FALSE
 +
 +
 +<code cpp>
 + if (widget->window == NULL) return FALSE;
 +</code>
 +
 +قد تحتاج لماذا هذا الكود هنا؟ هنا نقوم بعمل اختبار بسيط اذا كانت قيمة timeout صغيرة جدا مثلا 5ms فيحدث عند غلق التطبيق يكون تم تدمير النافذة بالفعل ويتم تنفيذ ال timeout function. فيمنع هذا السطر معالجة النافذة فى مثل تلك الحالات.
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/fadeout.png |Fade out}}
 +
 +
 +==== Waiting demo ====
 +
 +
 +
 +فى هذا المثال سنستخدم الشفافية لإنشاء "انتظار" فيه سنرسم 8 اسطر التى تشحب لخلق وهم بأن الخط يتحرك.. مثل هذه المؤثرات تستخدم لإعلام المستخدمين بأن مهمة طويلة تحدث فى الكواليس :) 
 +
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;math.h&gt;
 +
 +static gushort count = 0;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  static gdouble const trs[8][8] = {
 +      { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
 +      { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
 +      { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
 +      { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65},
 +      { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
 +      { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
 +      { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
 +      { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0, }
 +  };
 +
 +
 +  gint width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
 +
 +  cairo_translate(cr, width / 2, height /2);
 +
 +  gint i = 0;
 +  for (i = 0; i < 8; i++) {
 +      cairo_set_line_width(cr, 3);
 +      cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
 +      cairo_set_source_rgba(cr, 0, 0, 0, trs[count%8][i]);
 +
 +      cairo_move_to(cr, 0.0, -10.0);
 +      cairo_line_to(cr, 0.0, -40.0);
 +      cairo_rotate(cr, M_PI/4);
 +
 +      cairo_stroke(cr);
 +  }
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  count += 1;
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +  GtkWidget *darea;  
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 250, 150); 
 +
 +  gtk_window_set_title(GTK_WINDOW(window), "waiting demo");
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +  g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +
 +</code>
 +
 +
 +نرسم ال 8 اسطر بقيم الفا مختلفة
 +
 +
 +
 +<code cpp>
 + static gdouble const trs[8][8] = {
 +     { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
 +     { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
 +     { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
 +     { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65},
 +     { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
 +     { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
 +     { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
 +     { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0, }
 + };
 +</code>
 +
 +
 +هذه مصفوفة ثنائية الأبعاد مستخدمه فى هذا العرض.. هناك 8 صفوف كل منها لحالة.. كل من ال 8 اسطر يستخدمها
 +
 +
 +
 +<code cpp>
 + cairo_set_line_width(cr, 3);
 + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
 +</code>
 +
 +
 +نجعل الأسطر اسمك، ليصبحو اكثر وضوحا.. نرسم 
 +
 +
 +<code cpp>
 + cairo_set_source_rgba(cr, 0, 0, 0, trs[count%8][i]);
 +</code>
 +
 +هنا نحدد الشفافية لسطر
 +
 +
 +
 +
 +<code cpp>
 + cairo_move_to(cr, 0.0, -10.0);
 + cairo_line_to(cr, 0.0, -40.0);
 + cairo_rotate(cr, M_PI/4);
 +</code>
 +
 +
 +هذا الكود سيرسم كل من ال 8 خطوط
 +
 +<code cpp>
 + g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
 +</code>
 +
 +
 +نستخدم دالة مؤقت لعمل الأنيميشن.
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/waitingdemo.gif |Waiting demo}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== التركيب =====
 +
 +فى هذه الجزئية سنقوم بتعريف عمليات التركيب.
 +
 +
 +**Compositing** هو دمج اكثر من عنصر مرئى من مصادر مختلفة الى صورة واحدة. يستخدمو لإيهام ان كل تلك العناصر هى جزء من نفس المشهد.
 +يستخدم التركيب بكثرة فى صناعة الأفلام لإنشاء الحشود، عوالم جديدة.. الخ
 +
 +
 +
 +
 +==== العمليات ====
 +
 +يوجد العديد من عمليات التركيب، تقدم كايرو 14 عملية تركيب مختلفة.
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static void draw(cairo_t *cr, gint x, gint w,
 +    gint h, cairo_operator_t op)
 +{
 +
 +  cairo_t *first_cr, *second_cr;
 +  cairo_surface_t *first, *second;
 +
 +  first = cairo_surface_create_similar(cairo_get_target(cr),
 +      CAIRO_CONTENT_COLOR_ALPHA, w, h);
 +
 +  second = cairo_surface_create_similar(cairo_get_target(cr),
 +      CAIRO_CONTENT_COLOR_ALPHA, w, h);
 +
 +  first_cr = cairo_create(first);
 +  cairo_set_source_rgb(first_cr, 0, 0, 0.4);
 +  cairo_rectangle(first_cr, x, 20, 50, 50);
 +  cairo_fill(first_cr);
 +
 +  second_cr = cairo_create(second);
 +  cairo_set_source_rgb(second_cr, 0.5, 0.5, 0);
 +  cairo_rectangle(second_cr, x+10, 40, 50, 50);
 +  cairo_fill(second_cr);
 +
 +  cairo_set_operator(first_cr, op);
 +  cairo_set_source_surface(first_cr, second, 0, 0);
 +  cairo_paint(first_cr);
 +
 +  cairo_set_source_surface(cr, first, 0, 0);
 +  cairo_paint(cr);
 +
 +  cairo_surface_destroy(first);
 +  cairo_surface_destroy(second);
 +
 +  cairo_destroy(first_cr);
 +  cairo_destroy(second_cr);
 +
 +}
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  gint w, h;
 +  gint x, y;
 +
 +  cairo_operator_t oper[] = {
 +    CAIRO_OPERATOR_DEST_OVER, 
 +    CAIRO_OPERATOR_DEST_IN, 
 +    CAIRO_OPERATOR_OUT,
 +    CAIRO_OPERATOR_ADD, 
 +    CAIRO_OPERATOR_ATOP,
 +    CAIRO_OPERATOR_DEST_ATOP,
 +  };
 +
 +  gtk_window_get_size(GTK_WINDOW(widget), &w, &h);
 +
 +  cr = gdk_cairo_create(widget->window); 
 +
 +  gint i;
 +  for(x=20, y=20, i=0; i < 6; x+=80, i++) {
 +      draw(cr, x, w, h, oper[i] );
 +  }
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 510, 120);
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى المثال نعرض 6 عمليات تركيب على مربعين.
 +
 +
 +<code cpp>
 + first = cairo_surface_create_similar(cairo_get_target(cr),
 +     CAIRO_CONTENT_COLOR_ALPHA, w, h);
 +
 + second = cairo_surface_create_similar(cairo_get_target(cr),
 +     CAIRO_CONTENT_COLOR_ALPHA, w, h);
 +</code>
 +
 +
 +ننشئ سطحين.
 +
 +
 +
 +<code cpp>
 + first_cr = cairo_create(first);
 + cairo_set_source_rgb(first_cr, 0, 0, 0.4);
 + cairo_rectangle(first_cr, x, 20, 50, 50);
 + cairo_fill(first_cr);
 +</code>
 +
 +
 +نرسم مستطيل على السطح.
 +
 +
 +<code cpp>
 + cairo_set_operator(first_cr, op);
 + cairo_set_source_surface(first_cr, second, 0, 0);
 + cairo_paint(first_cr);
 +</code>
 +
 +
 +
 +نقوم بتطبيق عملية التركيب على السطحين.
 +
 +
 +
 +<code cpp>
 + cairo_set_source_surface(cr, first, 0, 0);
 + cairo_paint(cr);
 +</code>
 +
 +
 +
 +اخيرانقوم بالرسم على النافذة.
 +
 +
 +<code cpp>
 + cairo_operator_t oper[] = {
 +   CAIRO_OPERATOR_DEST_OVER, 
 +   CAIRO_OPERATOR_DEST_IN, 
 +   CAIRO_OPERATOR_OUT,
 +   CAIRO_OPERATOR_ADD, 
 +   CAIRO_OPERATOR_ATOP,
 +   CAIRO_OPERATOR_DEST_ATOP,
 + };
 +</code>
 +
 +
 +فى مثالنا استخدمنا هذه الستة عمليات تركيب
 +
 +In our example, we use these six compositing operations.
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/compositing.png |Compositing operations}}
 +
 +
 +
 +
 +
 +
 +===== Clipping and masking =====
 +
 +
 +
 +
 +
 +فى هذه الجزئية سنتحدث عن ال clipping -القصر- وال masking -التقنيع-
 +In this part of the Cairo tutorial, we will talk about clipping and masking.
 +
 +
 +
 +
 +
 +==== Clipping ====
 +
 +
 +
 +ال clipping هى عملية قصر للرسم فى منطقة محددة ويستخدم لأسباب متعلقة بالكفاءة ولإنشاء تأثيرات مثيرة.
 +
 +--سنستخدم كلمة قصاصة للتعبير عن clip
 +
 +=== تقصيص صورة ===
 +
 +
 +فى المثال سنوضح كيف نقوم بعمل تقصيص لصورة.
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;math.h&gt;
 +
 +cairo_surface_t *image;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  static gint pos_x = 128;
 +  static gint pos_y = 128;
 +  gint radius = 40;  
 +
 +  static gint delta[] = { 3, 3 };
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  gint width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
 +
 +  if (pos_x < 0 + radius) {
 +      delta[0] = rand() % 4 + 5;
 +  } else if (pos_x > width - radius) {
 +      delta[0] = -(rand() % 4 + 5);
 +  }
 +
 +  if (pos_y < 0 + radius) {
 +      delta[1] = rand() % 4 + 5;
 +  } else if (pos_y > height - radius) {
 +      delta[1] = -(rand() % 4 + 5);
 +  }
 +
 +  pos_x += delta[0];
 +  pos_y += delta[1];
 +
 +  cairo_set_source_surface(cr, image, 1, 1);
 +  cairo_arc(cr, pos_x, pos_y, radius, 0, 2*M_PI);
 +  cairo_clip(cr);
 +  cairo_paint(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +  gint width, height;  
 +
 +  image = cairo_image_surface_create_from_png("turnacastle.png");
 +  width = cairo_image_surface_get_width(image);
 +  height = cairo_image_surface_get_height(image); 
 +
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), width+2, height+2); 
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +  g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
 +
 +  gtk_main();
 +
 +  cairo_surface_destroy(image);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +فى المثال سنقوم بعمل قصاصة لصورة. دائرة تتحرك على الشاشة وتعرض الجزء الظاهر تحتها كأننا ننظر من ثقب.
 +
 +
 +<code cpp>
 + if (pos_x < 0 + radius) {
 +     delta[0] = rand() % 4 + 5;
 + } else if (pos_x > width - radius) {
 +     delta[0] = -(rand() % 4 + 5);
 + }
 +</code>
 +
 +
 +
 +اذا مرت الدائرة بالجانب الأيسر او الأيمن للنافذة يتم تغيير اتجاة حركة الدائرة عشوائيا ونفس الشئ للجانب الأعلى والأسفل.
 +
 +
 +<code cpp>
 + cairo_set_source_surface(cr, image, 1, 1);
 + cairo_arc(cr, pos_x, pos_y, radius, 0, 2*M_PI);
 +</code>
 +
 +
 +هنا نرسم الصورة والدائرة -لاحظ اننا لانرسم على النافذة فى هذه اللحظة.. فقط فى الذاكرة.
 +
 +
 +<code cpp>
 + cairo_clip(cr);
 +</code>
 +
 +
 +الدالة **cairo_clip** تقوم بتقصيص منطقة- منقطة القصاصة هى المسار الحالى المستخدم اللذى انشئ بواسطة الدالة **cairo_arc**
 +
 +
 +<code cpp>
 + cairo_paint(cr);
 +</code>
 +
 +
 +
 +
 +The **cairo_paint()** paints the current source everywhere within the current clip region.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/clipimage.png |Clipping image}}
 +
 +
 +=== تقصيص مستطيل ===
 +
 +
 +المثال التالى مستوحى من مثال وجدته فى امثلة Java2D
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;math.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cr = gdk_cairo_create(widget->window);
 +
 +  static gboolean xdirection = TRUE;
 +  static gint counter = 0;
 +
 +  int width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
 +
 +  static gdouble rotate = 0;
 +
 +  static gint bigx = 20;
 +  static gint bigy = 200;
 +  static gint delta = 1;
 +
 +  counter += 1;  
 +
 +
 +  if (bigx > width) {
 +      xdirection = FALSE;
 +      delta = -delta;
 +      bigx = width;
 +  }
 +
 +  if (bigx < 1) {
 +      bigx = 1;
 +      delta = -delta; 
 +  }
 +
 +  if (bigy > height) {
 +      xdirection = TRUE;
 +      delta = -delta;
 +      bigy = height;
 +  }
 +
 +  if (bigy < 1) {
 +      delta = -delta; 
 +      bigy = 1;
 +  }
 +
 +  if (xdirection) {
 +      bigx += delta;
 +  } else {
 +      bigy += delta;
 +  }
 +
 +  cairo_translate(cr, width / 2, height /2);
 +
 +  cairo_rectangle(cr, -bigx/2, -bigy/2, bigx-2, bigy-2);
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_set_line_width(cr, 1);  
 +  cairo_stroke(cr);
 +
 +  cairo_rotate(cr, rotate);
 +  rotate += 0.01;
 +
 +  cairo_rectangle(cr, -50, -25, 100, 50);
 +  cairo_stroke(cr);
 +
 +  GdkRectangle bigrect;
 +  GdkRectangle rect;
 +  GdkRectangle intersect;
 +
 +  bigrect.x = -bigx/2;
 +  bigrect.y = -bigy/2;
 +  bigrect.width = bigx -2;
 +  bigrect.height = bigy -2;
 +
 +  rect.x = -50;
 +  rect.y = -25;
 +  rect.width = 100;
 +  rect.height = 50;
 +
 +  gdk_rectangle_intersect(&bigrect, &rect, &intersect);
 +  cairo_rectangle(cr, intersect.x, intersect.y, intersect.width, intersect.height);
 +  cairo_fill(cr); 
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +int
 +main (int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200); 
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +  g_timeout_add(5, (GSourceFunc) time_handler, (gpointer) window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى المثال لدينا مستطيلين (واحد كبير واخر يدور- الكبير يتقلص وينمو بصورة مستمرة. والصغير بدور. هنا نقوم بتطبيق عملية التقاطع على الإثنين. فيتم تلوين منقطة التقاطع بينهم باللون الأسود.
 +لاحظ ان التقاطع ليس مستطيل تام ولكن للتسهيل سنقوم بتقريب المساحة لمستطيل
 +
 +<code cpp>
 + static gboolean xdirection = TRUE;
 +</code>
 +
 +
 +هذا المتغير يحدد اتجاه حركة المستطيل الكبير.
 +
 +
 +<code cpp>
 + if (bigx > width) {
 +     xdirection = FALSE;
 +     delta = -delta;
 +     bigx = width;
 + }
 +</code>
 +
 +
 +المستطيل الكبير بنفس عرض النافذة ونقوم بتغير الإتجاه، فيبدأ تقلص المستطيل فى اتجاه ص
 +
 +<code cpp>
 + cairo_rotate(cr, rotate);
 +</code>
 +
 +
 +الدالة **cairo_rotate** تدير المستطيل الأصغر.
 +
 +
 +<code cpp>
 + GdkRectangle bigrect;
 + GdkRectangle rect;
 + GdkRectangle intersect;
 +</code>
 +
 +
 +هنا نقوم بتعريف 3 مستطيلات. مستطيل **التقاطع** هو ناتج تقاطع المستطيلين.
 +
 +
 +<code cpp>
 + gdk_rectangle_intersect(&bigrect, &rect, &intersect);
 +</code>
 +
 +هنا نقوم بتطبيق عملية التقاطع.
 +
 +<code cpp>
 + cairo_rectangle(cr, intersect.x, intersect.y, intersect.width, intersect.height);
 + cairo_fill(cr); 
 +</code>
 +نرسم مساحة التقاطع.
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/cliprectangle.png |Clipping a rectangle}}
 +
 +
 +==== قناع ====
 +
 +قبل ان يتم تطبيق المصدر على السطح يتم ترشيحه اولا، يتم استخدام القناع كمرشح. ويقوم القناع بتحديد اى الأماكن اللتى سيتم تطبيق المصدر عليها.
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cairo_surface_t *surface;
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +
 +  cr = gdk_cairo_create(widget->window);
 +  surface = cairo_image_surface_create_from_png("omen.png");
 +  cairo_mask_surface(cr, surface, 0, 0);
 +  cairo_fill(cr);
 +
 +  cairo_surface_destroy(surface);
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 305, 100); 
 +
 +  gtk_window_set_title(GTK_WINDOW(window), "mask");
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى هذا المثال السيط نوضح الفكرة الأساسية وراء القناع. يحدد القناع اي الأماكن يتم فيها الرسم
 +
 +
 +<code cpp>
 + surface = cairo_image_surface_create_from_png("omen.png");
 + cairo_mask_surface(cr, surface, 0, 0);
 + cairo_fill(cr);
 +</code>
 +نستخدم الصورة كقناع ومن ثم عرضها على النافذة.
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/mask.png |Applying a mask}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== التحويلات =====
 +
 +فى هذه الجزئية سنتخدث عن التحويلات
 +
 +**affine transform** "التحول القريب" يتكون من 0 او اكثر من تحول (دوران -rotation- او scaling -توسيع- او shear -قص- ) والترجمة -shift- 
 +
 +عدة تحويلات خطية يمكن ان دمج سويا لمصفوفة واحدة.
 +**rotation** او الدوران يقوم بتدوير الجسم حول نقطة محددة.
 +**scaling** او التوسع يقوم بتكيير ابعاد الكائنات. ويكون معامل التوسيع واحد فى جميع الإتجاهات
 +**translation** او الترجمة هى تحويل يقوم بإزاحة كل النقاط الى مسافة ثابتة فى اتجاة ثابت
 +**shear** او القص هو تحويل يقوم بإزاحة الكائن بصورة عمودية على محور معين مع قيمة اعلى اعلى فى محور عن الآخر 
 +#FIXME: توضيح افضل للقص
 +
 +**An affine transform** is composed of zero or more linear transformations (rotation, scaling or shear) and translation (shift). Several linear transformations can be combined into a single matrix.
 +A **rotation** is a transformation that moves a rigid body around a fixed point.
 +A **scaling** is a transformation that enlarges or diminishes objects. The scale factor is the same in all directions.
 +A **translation** is a transformation that moves every point a constant distance in a specified direction.
 +A **shear** is a transformation that moves an object perpendicular to a given axis, with greater value on one side of the axis than the other.
 +
 +
 +
 +
 +
 +
 +
 +sources: (wikipedia.org, freedictionary.com)
 +
 +
 +
 +
 +==== الترجمة ====
 +
 +المثال التالى يوصف ترجمة بسيطة.
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 20, 20, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_translate(cr, 100, 100);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 20, 20, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK (on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK (gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 300, 230); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +المثال يرسم مستطيل، ثم نقوم بعمل ترجمة ونرسم نفس المستطيل مرة اخرى.
 +
 +<code cpp>
 + cairo_translate(cr, 100, 100);
 +</code>
 +
 +**cairo_translate()** تعدل مصفوفة التحويل عن طريق ترجمة نقطة اصل مساحة المستخدم.. فى حالتنا هذه قمنا بتحويل نقطة الأصل 100 وحدة فى الإتجاهين.
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/translate.png |Translate}}
 +
 +
 +
 +
 +==== الدواران ====
 +
 +المثال التالى يوضح لنا مفهوم الدوران
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;math.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 20, 20, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_translate(cr, 150, 100);
 +  cairo_rotate(cr, M_PI/2);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 20, 20, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK (on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK (gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 300, 230); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +المثال نرسم فيه مستطيل، ونقوم بعمل ترجمة ودوران ثم نرسم نفس المستطيل مرة اخرى
 +
 +
 +<code cpp>
 + cairo_translate(cr, 150, 100);
 + cairo_rotate(cr, M_PI/2);
 +</code>
 +
 +
 +اولا نقوم بإزاحة نقطة الأصل للمستخدم ونقوم بتدويرها بمقدار 180درجة -لاحظ ان الزاوية بالتقدير الدائرى-
 +
 +2 ط = 360
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/rotate.png |Rotate}}
 +
 +
 +==== Scale ====
 +
 +
 +
 +المثال التالى يتعرض لعملية ال scaling -التوسيع-
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_save(cr);
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 20, 30, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +  cairo_restore(cr);
 +
 +  cairo_save(cr);
 +  cairo_translate(cr, 130, 30);
 +  cairo_scale(cr, 0.7, 0.7);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 0, 0, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +  cairo_restore(cr);
 +
 +  cairo_save(cr);
 +  cairo_translate(cr, 220, 30);
 +  cairo_scale(cr, 1.5, 1.5);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 0, 0, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +  cairo_restore(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK (on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK (gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 360, 140); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +هذه المرة نجعل المستطيل الأصلى اصغر ثم اكبر بإستخدام معامل توسيع محدد
 +
 +<code cpp>
 + cairo_save(cr);
 + ...
 + cairo_restore(cr);
 +</code>
 +
 +
 +
 +
 +We want to perform two scaling operations on the initial rectangle. Therefore, we need to save the initial transformation matrix. This is done by a pair of **cairo_save()** and **cairo_restore()** functions.
 +
 +
 + 
 +
 +<code cpp>
 + cairo_translate(cr, 130, 30);
 + cairo_scale(cr, 0.7, 0.7);
 +</code>
 +
 +
 +ننقل نقطة الأصل ونقوم بالتوسيع بنسبة 0.7
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/scale.png |Scale}}
 +
 +
 +
 +==== القص ====
 +
 +
 +فى المثال التالى سنقوم بعمل قص shearing
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cairo_matrix_t matrix;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_save(cr);
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 20, 30, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +  cairo_restore(cr);
 +
 +  cairo_save(cr);
 +  cairo_translate(cr, 130, 30);
 +  cairo_matrix_init(&matrix,
 +      1.0, 0.5,
 +      0.0, 1.0,
 +      0.0, 0.0);
 +
 +  cairo_transform (cr, &matrix);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 0, 0, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +  cairo_restore(cr);
 +
 +  cairo_save(cr);
 +  cairo_translate(cr, 220, 30);
 +  cairo_matrix_init(&matrix,
 +      1.0, 0.0,
 +      0.7, 1.0,
 +      0.0, 0.0);
 +
 +  cairo_transform(cr, &matrix);
 +
 +  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
 +  cairo_rectangle(cr, 0, 0, 80, 50);
 +  cairo_stroke_preserve(cr);
 +  cairo_set_source_rgb(cr, 1, 1, 1);
 +  cairo_fill(cr);
 +  cairo_restore(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 360, 140); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +
 +In this code example, we perform two shear transformations. For a shear transformation, we do not have a special 
 +function. We must use matrices.
 +
 +
 +
 +
 +<code cpp>
 + cairo_matrix_t matrix;
 +</code>
 +
 +**cairo_matrix_t** هى هيكل يحمل تحول قريب
 +#FIXME: اعادة صياغة
 +
 +
 +The **cairo_matrix_t** is a structure that holds an affine transformation.
 +
 +
 +
 +
 +<code cpp>
 + cairo_matrix_init(&matrix,
 +    1.0, 0.5,
 +    0.0, 1.0,
 +    0.0, 0.0);
 +
 + cairo_transform (cr, &matrix);
 +</code>
 +
 +
 +
 +هذا التحول يقص قيم ص بمقدار 0.5 من قيم س 
 +
 +
 +<code cpp>
 + cairo_matrix_init(&matrix,
 +     1.0, 0.0,
 +     0.7, 1.0,
 +     0.0, 0.0);
 +
 + cairo_transform(cr, &matrix);
 +</code>
 +
 +
 +وهذا التحول يضاعف قيم س على الإحداثيات بمقدار 0.7 من ص
 +
 +And this transformation multiplies the x value of each coordinate by 0.7 of the y.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/shear.png |Shear}}
 +
 +
 +
 +
 +
 +==== Ellipses ====
 +
 +فى المثال التالى سننشئ شكل معقد عبر الدوران ومجموعة قطاعات.
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  gint width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height); 
 +
 +  cairo_set_line_width(cr, 0.5);
 +  cairo_translate(cr, width/2, height/2);
 +  cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
 +  cairo_stroke(cr);
 +
 +  gint i;
 +
 +  cairo_save(cr);
 +  for ( i = 0; i < 36; i++) {
 +      cairo_rotate(cr, i*M_PI/36);
 +      cairo_scale(cr, 0.3, 1);
 +      cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
 +      cairo_restore(cr);
 +      cairo_stroke(cr);
 +      cairo_save(cr);
 +  }
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 350, 250); 
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +<code cpp>
 + cairo_translate(cr, width/2, height/2);
 + cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
 + cairo_stroke(cr);
 +</code>
 +
 +
 +
 +فى منتصف النافذة ننشئ دائرة
 +In the middle of the GTK+ window, we create a circle. This will be a bounding circle for our ellipses.
 +
 +
 +
 +
 +<code cpp>
 + cairo_save(cr);
 + for ( i = 0; i < 36; i++) {
 +     cairo_rotate(cr, i*M_PI/36);
 +     cairo_scale(cr, 0.3, 1);
 +     cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
 +     cairo_restore(cr);
 +     cairo_stroke(cr);
 +     cairo_save(cr);
 + }
 +</code>
 +
 +
 +ننشئ 36 قطع ناقص على طول الدائرة ونقوم بتدويرهم لننشئ شكل مثير جدا :)
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/ellipserotate.png |Ellipse rotate}}
 +
 +
 +
 +
 +==== نجمة ====
 +
 +المثال التالى يعرض تدوير وتوسيع نجمة.
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;math.h&gt;
 +
 +int points[11][2] = { 
 +    { 0, 85 }, 
 +    { 75, 75 }, 
 +    { 100, 10 }, 
 +    { 125, 75 }, 
 +    { 200, 85 },
 +    { 150, 125 }, 
 +    { 160, 190 },
 +    { 100, 150 }, 
 +    { 40, 190 },
 +    { 50, 125 },
 +    { 0, 85 } 
 +};
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  static gdouble angle = 0;
 +  static gdouble scale = 1;
 +  static gdouble delta = 0.01;
 +
 +  gint width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_set_source_rgb(cr, 0, 0.44, 0.7);
 +  cairo_set_line_width(cr, 1);
 +
 +  cairo_translate(cr, width / 2, height / 2 );
 +  cairo_rotate(cr, angle);
 +  cairo_scale(cr, scale, scale);
 +
 +  gint i;
 +
 +  for ( i = 0; i < 10; i++ ) {
 +      cairo_line_to(cr, points[i][0], points[i][1]);
 +  }
 +
 +  cairo_close_path(cr);
 +  cairo_fill(cr);
 +  cairo_stroke(cr);
 +
 +  if ( scale < 0.01 ) {
 +      delta = -delta;
 +  } else if (scale > 0.99) {
 +      delta = -delta;
 +  }
 +
 +  scale += delta;
 +  angle += 0.01;
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  gtk_widget_add_events (window, GDK_BUTTON_PRESS_MASK);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 + 
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_title(GTK_WINDOW(window), "star");
 +  gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  g_timeout_add(10, (GSourceFunc) time_handler, (gpointer) window);  
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +فى المثال ننشئ كائن نجمة، ونقوم بترجمته وتدويره ثم توسيعه.
 +
 +
 +
 +
 +<code cpp>
 + cairo_translate(cr, width / 2, height / 2 );
 + cairo_rotate(cr, angle);
 + cairo_scale(cr, scale, scale 
 +</code>
 +
 +
 +
 +نقوم بإزاحة النجمة الى منتصف النافذة وتدويرها وتوسيعها.
 +
 +
 +
 +<code cpp>
 +  for ( i = 0; i < 10; i++ ) {
 +      cairo_line_to(cr, points[i][0], points[i][1]);
 +  }
 +
 +  cairo_close_path(cr);
 +  cairo_fill(cr);
 +  cairo_stroke(cr);
 +</code>
 +
 +
 +
 +هنا نرسم كائن النجمة.
 +
 +
 +<code cpp>
 + if ( scale < 0.01 ) {
 +     delta = -delta;
 + } else if (scale > 0.99) {
 +     delta = -delta;
 + }
 +</code>
 +
 +
 +
 +هذه الأسطر تتحكم فى نمو او تقلص النجمة.
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/star.gif |Star}}
 +
 +
 +===== النص فى كايرو =====
 +
 +
 +فى هذه الجزئية سنتعامل مع النصوص.
 +
 +==== Soulmate ====
 +
 +
 +
 +فى التالى سنرسم بعض النص على النافذة.
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); 
 +
 +  cairo_select_font_face(cr, "Purisa",
 +      CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_BOLD);
 +
 +  cairo_set_font_size(cr, 13);
 +
 +  cairo_move_to(cr, 20, 30);
 +  cairo_show_text(cr, "Most relationships seem so transitory");  
 +  cairo_move_to(cr, 20, 60);
 +  cairo_show_text(cr, "They're all good but not the permanent one");
 +
 +  cairo_move_to(cr, 20, 120);
 +  cairo_show_text(cr, "Who doesn't long for someone to hold");
 +
 +  cairo_move_to(cr, 20, 150);
 +  cairo_show_text(cr, "Who knows how to love you without being told");
 +  cairo_move_to(cr, 20, 180);
 +  cairo_show_text(cr, "Somebody tell me why I'm on my own");
 +  cairo_move_to(cr, 20, 210);
 +  cairo_show_text(cr, "If there's a soulmate for everyone");
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +
 +int main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 420, 250); 
 +  gtk_window_set_title(GTK_WINDOW(window), "Soulmate");
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +هنا عرضنا جزء كلمات اغنية soulmate ل Natasha Bedingfields 
 +
 +
 +<code cpp>
 + cairo_select_font_face(cr, "Purisa",
 +    CAIRO_FONT_SLANT_NORMAL,
 +    CAIRO_FONT_WEIGHT_BOLD);
 +</code>
 +
 +هنا حددنا الخط واستخدمنا Pursia bold
 +
 +
 +<code cpp>
 + cairo_set_font_size(cr, 13);
 +</code>
 +
 +نحدد حجم الخط
 +
 +
 +<code cpp>
 + cairo_move_to(cr, 20, 30);
 + cairo_show_text(cr, "Most relationships seem so transitory"); 
 +</code>
 +
 +
 +
 +ننتقل الى النقطة حيث نرسم النص بإستخدام **cairo_show_text()**
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/soulmate.png |Soulmate}}
 +
 +
 +==== حرف حرف ====
 +
 +
 +فى هذا التأثير، سنعرض النص حرف حرف مع بعض التأخير.
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +gpointer text[7] = { "Z", "e", "t", "C", "o", "d", "e" };
 +gboolean timer = TRUE;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cairo_text_extents_t extents;
 +  static gint count = 0;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_select_font_face(cr, "Courier",
 +      CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_BOLD);
 +
 +  cairo_set_font_size(cr, 35);
 +  cairo_set_source_rgb(cr, 0.2, 0.2, 0.2); 
 +
 +  gint i;
 +  gint x = 0;
 +
 +  for (i = 0; i < count; i++) {
 +      cairo_text_extents(cr, text[i], &extents);
 +      x += extents.width + 2;
 +      cairo_move_to(cr, x + 30, 50);
 +      cairo_show_text(cr, text[i]);  
 +  }
 +
 +  count++;
 +
 +  if (count == 8) {
 +      timer = FALSE;
 +      count = 0;
 +  }
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +
 +  if (!timer) return FALSE;
 +
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +
 +int main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 300, 90); 
 +  gtk_window_set_title(GTK_WINDOW(window), "ZetCode");
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) window);
 +
 +  gtk_widget_show_all(window);
 +
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +
 +</code>
 +
 +
 +
 +فى هذا المثال، سنقوم برسم النص "ZetCode" على النافذة حرف حرف مع بعض التأخير.
 +
 +
 +
 +<code cpp>
 + gpointer text[7] = { "Z", "e", "t", "C", "o", "d", "e" };
 +</code>
 +
 +ننشئ مصفوفة من السلاسل الحرفية
 +
 +
 +<code cpp>
 + cairo_select_font_face(cr, "Courier",
 +    CAIRO_FONT_SLANT_NORMAL,
 +    CAIRO_FONT_WEIGHT_BOLD);
 +</code>
 +نختار الخط Courier
 +
 +<code cpp>
 + for (i = 0; i < count; i++) {
 +    cairo_text_extents(cr, text[i], &extents);
 +    x += extents.width + 2;
 +    cairo_move_to(cr, x + 30, 50);
 +    cairo_show_text(cr, text[i]);  
 + }
 +</code>
 +
 +نرسم النص حرف حرف. 
 +**extents.width**  تعطينا العرض للحرف الحالى.
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/zetcode.gif |ZetCode}}
 +
 +
 +
 +==== Puff ====
 +
 +
 +
 +فى المثال التالى سننشئ تأثير puff.. فى المثال نعرض نص فى المنتصف يكبر حتى حد معين ثم يتلاشى
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +gpointer text[7] = { "Z", "e", "t", "C", "o", "d", "e" };
 +gboolean timer = TRUE;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cairo_text_extents_t extents;
 +
 +  static gdouble alpha = 1.0;
 +  static gdouble size = 1;
 +
 +
 +  gint x = widget->allocation.width / 2;
 +  gint y = widget->allocation.height / 2;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_set_source_rgb(cr, 0.5, 0, 0); 
 +  cairo_paint(cr);
 +
 +  cairo_select_font_face(cr, "Courier",
 +      CAIRO_FONT_SLANT_NORMAL,
 +      CAIRO_FONT_WEIGHT_BOLD);
 +
 +  size += 0.8;
 +
 +  if (size > 20) {
 +      alpha -= 0.01;
 +  }
 +
 +  cairo_set_font_size(cr, size);
 +
 +  cairo_set_source_rgb(cr, 1, 1, 1); 
 +
 +  cairo_text_extents(cr, "ZetCode", &extents);
 +  cairo_move_to(cr, x - extents.width/2, y);
 +  cairo_text_path(cr, "ZetCode");
 +  cairo_clip(cr);
 +  cairo_stroke(cr);
 +  cairo_paint_with_alpha(cr, alpha);
 +
 +  if (alpha <= 0) {
 +      timer = FALSE;
 +  }
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +
 +  if (!timer) return FALSE;
 +
 +  gtk_widget_queue_draw(widget);
 +
 +  return TRUE;
 +}
 +
 +
 +int main (int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 350, 200); 
 +  gtk_window_set_title(GTK_WINDOW(window), "puff");
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  g_timeout_add(14, (GSourceFunc) time_handler, (gpointer) window);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +
 +
 +فى هذا المثال سننشئ نص يكبر ويتلاشى على النافذة. 
 +
 +
 +
 +
 +<code cpp>
 + gint x = widget->allocation.width / 2;
 + gint y = widget->allocation.height / 2;
 +</code>
 +
 +
 +
 +
 +Coordinates of the middle point.
 +
 +
 +
 +
 +<code cpp>
 + cairo_set_source_rgb(cr, 0.5, 0, 0); 
 + cairo_paint(cr);
 +</code>
 +
 +
 +
 +نجعل الخلفية احمر غامق.
 +
 +
 +
 +<code cpp>
 + size += 0.8;
 +</code>
 +
 +
 +
 +
 +مع كل دورة يزيد حجم الخط بمقدار 0.8
 +
 +
 +
 +<code cpp>
 + if (size > 20) {
 +     alpha -= 0.01;
 + }
 +</code>
 +
 +
 +
 +
 +التلاشى يبدأ عندما يزيد حجم الخط عن 20
 +
 +
 +
 +
 +<code cpp>
 + cairo_text_extents(cr, "ZetCode", &extents);
 +</code>
 +
 +نحصل على مقاييس النص.
 +
 +
 +
 +
 +<code cpp>
 + cairo_move_to(cr, x - extents.width/2, y);
 +</code>
 +
 +
 +نستخدم مقاييس النص لسنترته -وضعه بالمنتصف- على النافذه
 +
 +
 +<code cpp>
 + cairo_text_path(cr, "ZetCode");
 + cairo_clip(cr);
 +</code>
 +
 +
 +نحصل على مسار النص ونحدد منطقة القصاصة الحالية
 +
 +
 +<code cpp>
 + cairo_stroke(cr);
 + cairo_paint_with_alpha(cr, alpha);
 +</code>
 +
 +
 +
 +نرسم المسار مع استخدام قيمة الفا
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/puff.gif |Puff}}
 +
 +
 +===== الصور فى كايرو =====
 +
 +
 +
 +فى هذه الجزئية سنتحدث عن الصور. سنوضح كيفية عرض صورة على نافذة. وسنقوم بعمل بعض التأثيرات على الصور.
 +
 +
 +
 +
 +==== عرض صورة ====
 +
 +فى اول مثال سنقوم بعرض صورة
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +cairo_surface_t *image;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create (widget->window);
 +
 +  cairo_set_source_surface(cr, image, 10, 10);
 +  cairo_paint(cr);
 +
 +  cairo_destroy(cr);
 +
 +  return FALSE;
 +}
 +
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  image = cairo_image_surface_create_from_png("plaveckycastle.png");
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(window, "expose-event",
 +      G_CALLBACK (on_expose_event), NULL);
 +  g_signal_connect(window, "destroy",
 +      G_CALLBACK (gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 320, 250); 
 +  gtk_widget_set_app_paintable(window, TRUE);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  cairo_surface_destroy(image);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +المثال يعرض صورة 300x225 .. تستطيع تحميلها من <a href="../images/plaveckycastle.png">هنا</a>.
 +هذه قلعة medieval فى Palvecke Podharadie فى غرب سلوفاكيا
 +
 +
 +<code cpp>
 + image = cairo_image_surface_create_from_png("plaveckycastle.png");
 +</code>
 +
 +
 +ننشئ سطح صورة من صورة PNG ولأسباب متعلفة بالكفاءة يتم استدعائها فى الدالة الرئيسية
 +
 +
 +
 +<code cpp>
 + cairo_set_source_surface(cr, image, 10, 10);
 +</code>
 +نحدد المصدر للرسم من سطح الصورة المنشئ سابقا
 +
 +
 +
 +<code cpp>
 + cairo_paint(cr);
 +</code>
 +
 +
 +
 +نرسم على النافذة
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/castleimage.png |Image}}
 +
 +
 +
 +==== تأثير الستارة ====
 +
 +فى هذا المثال سنقوم بتأثير كاننا نرفع ستارة من على صورة من اعلى لأسفل حتى تظهر الصورة كاملة.
 +
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +gboolean timer = TRUE;
 +cairo_surface_t *image;
 +
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cairo_t *ic;
 +
 +  cairo_surface_t *surface;
 +
 +  static gdouble angle = 0;
 +  static gint image_width = 0;
 +  static gint image_height = 0;
 +
 +  static gint w = 0;
 +  static gint h = 0;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  gint width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height); 
 +
 +  image_width = cairo_image_surface_get_width(image);
 +  image_height = cairo_image_surface_get_height(image);
 +  w = image_width;
 +
 +  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height);
 +  ic = cairo_create(surface);
 +
 +  cairo_rectangle(ic, 0, 0, w, h);
 +  cairo_fill(ic);
 +
 +  h += 1;
 +  if ( h == image_height) timer = FALSE;
 +
 +  cairo_set_source_surface(cr, image, 10, 10);
 +  cairo_mask_surface(cr, surface, 10, 10);
 +
 +  cairo_surface_destroy(surface);
 +
 +  cairo_destroy(cr);
 +  cairo_destroy(ic);
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler(GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +
 +  if (!timer) return FALSE;
 +
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  image = cairo_image_surface_create_from_png("plaveckycastle.png");
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 325, 250); 
 +  gtk_window_set_title(GTK_WINDOW(window), "blind down");
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  g_timeout_add(15, (GSourceFunc) time_handler, (gpointer) window);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  cairo_surface_destroy(image);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +الفكرة وراء هذا التأثير بسيطة جدا اذا كانت الصورة بإرتفاع م بكسل فإننا نقوم برسم الخطوط من 0 الى م بإرتفاع 1 بكسل حتى تظهر الصورة كاملة.
 +
 +<code cpp>
 + cairo_t *cr;
 + cairo_t *ic;
 +</code>
 +
 +
 +هنا نقوم بتعريف سياقين كايرو، واحد ليربط بالنافذة والآخر بالصورة.
 +
 +
 +<code cpp>
 + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height);
 + ic = cairo_create(surface);
 +</code>
 +
 +ننشئ سطح صورة ومنه ننشئ سياق كايرو.
 +
 +<code cpp>
 + cairo_rectangle(ic, 0, 0, w, h);
 + cairo_fill(ic);
 +</code>
 +
 +
 +هنا نرسم ابتدائيا مستطيل فارغ وفى كل دورة يزداد 1 بكسل والصورة المنشئة بهذه الطريقة سوق تخدم كقناع لاحقا.
 +
 +
 +<code cpp>
 +  h += 1;
 +  if ( h == image_height) timer = FALSE;
 +</code>
 +
 +
 +هنا نوقف المؤقت عندما يتم رسم الصورة كاملة -الإرتفاع الحالى = ارتفاع الصورة.
 +
 +<code cpp>
 + cairo_set_source_surface(cr, image, 10, 10);
 + cairo_mask_surface(cr, surface, 10, 10);
 +</code>
 +
 +
 +صورة القلعة يتم استخدامها كمصدر للرسم والدالة **cairo_mask_surface** ترسم المصدر الحالى عبر قناة الفا للسطح كقناع.
 +
 +==== تأثير الطيف ====
 +
 +
 +لم استطع ان افكر فى اسم افضل من "تأثير الطيف". ربما يتذكر بعضكم الأيام الخوالى مع حاسوب ZX Spectrum.
 +فى المثال التالى سنقوم بتحميل صورة تظهر تدريجيا على الشاشة. 
 +
 +#FIXME :تنفيذ المثال 
 +
 +
 +<code cpp>
 +#include &lt;cairo.h&gt;
 +#include &lt;gtk/gtk.h&gt;
 +
 +
 +gboolean timer = TRUE;
 +cairo_surface_t *image;
 +
 +static gboolean
 +on_expose_event(GtkWidget *widget,
 +    GdkEventExpose *event,
 +    gpointer data)
 +{
 +  cairo_t *cr;
 +  cairo_t *ic;
 +
 +  cairo_surface_t *surface;
 +
 +  static gdouble angle = 0;
 +  static gint w = 0;
 +  static gint h = 0;
 +
 +  static gint image_width = 0;
 +  static gint image_height = 0;
 +
 +  static gint count = 0;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  gint width, height;
 +  gtk_window_get_size(GTK_WINDOW(widget), &width, &height); 
 +
 +  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height);  
 +
 +  image_width = cairo_image_surface_get_width(image);
 +  image_height = cairo_image_surface_get_height(image);
 +  w = image_width;  
 +
 +  ic = cairo_create(surface);
 +
 +  gint i, j;
 +  for (i = 0; i <= image_height; i+=7) {
 +      for (j=0 ; j < count; j++) {
 +          cairo_move_to(ic, 0, i+j);
 +          cairo_line_to(ic, w, i+j);
 +      }
 +  }
 +
 +  count++;
 +  if ( count == 8) timer = FALSE;
 +
 +  cairo_stroke(ic);
 +
 +  cairo_set_source_surface(cr, image, 10, 10);
 +  cairo_mask_surface(cr, surface, 10, 10);
 +
 +  cairo_surface_destroy(surface);
 +
 +  cairo_destroy(cr);
 +  cairo_destroy(ic);
 +  return FALSE;
 +}
 +
 +static gboolean
 +time_handler (GtkWidget *widget)
 +{
 +  if (widget->window == NULL) return FALSE;
 +
 +  if (!timer) return FALSE;
 +
 +  gtk_widget_queue_draw(widget);
 +  return TRUE;
 +}
 +
 +int main(int argc, char *argv[])
 +{
 +  GtkWidget *window;
 +
 +  image = cairo_image_surface_create_from_png("plaveckycastle.png");
 +
 +  gtk_init(&argc, &argv);
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
 +  g_signal_connect(G_OBJECT(window), "expose-event",
 +      G_CALLBACK(on_expose_event), NULL);
 +  g_signal_connect(G_OBJECT(window), "destroy",
 +      G_CALLBACK(gtk_main_quit), NULL);
 +
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 325, 250); 
 +
 +  gtk_widget_set_app_paintable(window, TRUE);
 +  g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
 +
 +  gtk_widget_show_all(window);
 +
 +  gtk_main();
 +
 +  cairo_surface_destroy(image);
 +
 +  return 0;
 +}
 +</code>
 +
 +
 +المثال مشابه للمثال السابق ولكن هنا نقوم بتقسيم الصورة الى 8 خطوط كل قطعة يزداد حجمها بمقدار 1 بكسل وتعمل كقناع لعرض صورة القلعة
 +
 +In most details, the example is similar to the previous one. This time, we divide the image into n parts consisting of 8 lines.
 +Each cycle each part of the image will get bigger by one pixel. The created image will serve again as a mask for displaying
 +the image of the castle.
 +
 +
 +
 +
 +<code cpp>
 + gint i, j;
 + for (i = 0; i <= image_height; i+=7) {
 +     for (j=0 ; j < count; j++) {
 +         cairo_move_to(ic, 0, i+j);
 +         cairo_line_to(ic, w, i+j);
 +     }
 + }
 +</code>
 +
 +
 +هنا المنطق وراء هذا المثال، نرسم الخطوط تدريجيا الى كل جزء من الأجزاء
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/spectrum.png |Spectrum}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== ودجت مخصص =====
 +
 +
 +
 +فى هذه الجزئية سنقوم بعمل ودجت مخصص بإستخدام كايرو.
 +
 +
 +
 +==== ودجت CPU ====
 +
 +
 +فى المثال سننشئ ودجت لل CPU
 +
 +
 +<code cpp>
 +/* cpu.h */
 +
 +#ifndef __CPU_H
 +#define __CPU_H
 +
 +#include &lt;gtk/gtk.h&gt;
 +#include &lt;cairo.h&gt;
 +
 +G_BEGIN_DECLS
 +
 +
 +#define GTK_CPU(obj) GTK_CHECK_CAST(obj, gtk_cpu_get_type (), GtkCpu)
 +#define GTK_CPU_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_cpu_get_type(), GtkCpuClass)
 +#define GTK_IS_CPU(obj) GTK_CHECK_TYPE(obj, gtk_cpu_get_type())
 +
 +
 +typedef struct _GtkCpu GtkCpu;
 +typedef struct _GtkCpuClass GtkCpuClass;
 +
 +
 +struct _GtkCpu {
 +  GtkWidget widget;
 +
 +  gint sel;
 +};
 +
 +struct _GtkCpuClass {
 +  GtkWidgetClass parent_class;
 +};
 +
 +
 +GtkType gtk_cpu_get_type(void);
 +void gtk_cpu_set_sel(GtkCpu *cpu, gint sel);
 +GtkWidget * gtk_cpu_new();
 +
 +
 +G_END_DECLS
 +
 +#endif /* __CPU_H */
 +</code>
 +
 +<code cpp>
 +/* cpu.c */
 +
 +#include "cpu.h"
 +
 +
 +static void gtk_cpu_class_init(GtkCpuClass *klass);
 +static void gtk_cpu_init(GtkCpu *cpu);
 +static void gtk_cpu_size_request(GtkWidget *widget,
 +    GtkRequisition *requisition);
 +static void gtk_cpu_size_allocate(GtkWidget *widget,
 +    GtkAllocation *allocation);
 +static void gtk_cpu_realize(GtkWidget *widget);
 +static gboolean gtk_cpu_expose(GtkWidget *widget,
 +    GdkEventExpose *event);
 +static void gtk_cpu_paint(GtkWidget *widget);
 +static void gtk_cpu_destroy(GtkObject *object);
 +
 +
 +GtkType
 +gtk_cpu_get_type(void)
 +{
 +  static GtkType gtk_cpu_type = 0;
 +
 +
 +  if (!gtk_cpu_type) {
 +      static const GtkTypeInfo gtk_cpu_info = {
 +          "GtkCpu",
 +          sizeof(GtkCpu),
 +          sizeof(GtkCpuClass),
 +          (GtkClassInitFunc) gtk_cpu_class_init,
 +          (GtkObjectInitFunc) gtk_cpu_init,
 +          NULL,
 +          NULL,
 +          (GtkClassInitFunc) NULL
 +      };
 +      gtk_cpu_type = gtk_type_unique(GTK_TYPE_WIDGET, &gtk_cpu_info);
 +  }
 +
 +
 +  return gtk_cpu_type;
 +}
 +
 +void
 +gtk_cpu_set_state(GtkCpu *cpu, gint num)
 +{
 +   cpu->sel = num;
 +   gtk_cpu_paint(GTK_WIDGET(cpu));
 +}
 +
 +
 +GtkWidget * gtk_cpu_new()
 +{
 +   return GTK_WIDGET(gtk_type_new(gtk_cpu_get_type()));
 +}
 +
 +
 +static void
 +gtk_cpu_class_init(GtkCpuClass *klass)
 +{
 +  GtkWidgetClass *widget_class;
 +  GtkObjectClass *object_class;
 +
 +
 +  widget_class = (GtkWidgetClass *) klass;
 +  object_class = (GtkObjectClass *) klass;
 +
 +  widget_class->realize = gtk_cpu_realize;
 +  widget_class->size_request = gtk_cpu_size_request;
 +  widget_class->size_allocate = gtk_cpu_size_allocate;
 +  widget_class->expose_event = gtk_cpu_expose;
 +
 +  object_class->destroy = gtk_cpu_destroy;
 +}
 +
 +
 +static void
 +gtk_cpu_init(GtkCpu *cpu)
 +{
 +   cpu->sel = 0;
 +}
 +
 +
 +static void
 +gtk_cpu_size_request(GtkWidget *widget,
 +    GtkRequisition *requisition)
 +{
 +  g_return_if_fail(widget != NULL);
 +  g_return_if_fail(GTK_IS_CPU(widget));
 +  g_return_if_fail(requisition != NULL);
 +
 +  requisition->width = 80;
 +  requisition->height = 100;
 +}
 +
 +
 +static void
 +gtk_cpu_size_allocate(GtkWidget *widget,
 +    GtkAllocation *allocation)
 +{
 +  g_return_if_fail(widget != NULL);
 +  g_return_if_fail(GTK_IS_CPU(widget));
 +  g_return_if_fail(allocation != NULL);
 +
 +  widget->allocation = *allocation;
 +
 +  if (GTK_WIDGET_REALIZED(widget)) {
 +     gdk_window_move_resize(
 +         widget->window,
 +         allocation->x, allocation->y,
 +         allocation->width, allocation->height
 +     );
 +   }
 +}
 +
 +
 +static void
 +gtk_cpu_realize(GtkWidget *widget)
 +{
 +  GdkWindowAttr attributes;
 +  guint attributes_mask;
 +
 +  g_return_if_fail(widget != NULL);
 +  g_return_if_fail(GTK_IS_CPU(widget));
 +
 +  GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
 +
 +  attributes.window_type = GDK_WINDOW_CHILD;
 +  attributes.x = widget->allocation.x;
 +  attributes.y = widget->allocation.y;
 +  attributes.width = 80;
 +  attributes.height = 100;
 +
 +  attributes.wclass = GDK_INPUT_OUTPUT;
 +  attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
 +
 +  attributes_mask = GDK_WA_X | GDK_WA_Y;
 +
 +  widget->window = gdk_window_new(
 +     gtk_widget_get_parent_window (widget),
 +     & attributes, attributes_mask
 +  );
 +
 +  gdk_window_set_user_data(widget->window, widget);
 +
 +  widget->style = gtk_style_attach(widget->style, widget->window);
 +  gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
 +}
 +
 +
 +static gboolean
 +gtk_cpu_expose(GtkWidget *widget,
 +    GdkEventExpose *event)
 +{
 +  g_return_val_if_fail(widget != NULL, FALSE);
 +  g_return_val_if_fail(GTK_IS_CPU(widget), FALSE);
 +  g_return_val_if_fail(event != NULL, FALSE);
 +
 +  gtk_cpu_paint(widget);
 +
 +  return FALSE;
 +}
 +
 +
 +static void
 +gtk_cpu_paint(GtkWidget *widget)
 +{
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_translate(cr, 0, 7);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_paint(cr);
 +
 +  gint pos = GTK_CPU(widget)->sel;
 +  gint rect = pos / 5;
 +
 +  cairo_set_source_rgb(cr, 0.2, 0.4, 0);
 +
 +  gint i;
 +  for ( i = 1; i <= 20; i++) {
 +      if (i > 20 - rect) {
 +          cairo_set_source_rgb(cr, 0.6, 1.0, 0);
 +      } else {
 +          cairo_set_source_rgb(cr, 0.2, 0.4, 0);
 +      }
 +      cairo_rectangle(cr, 8, i*4, 30, 3);
 +      cairo_rectangle(cr, 42, i*4, 30, 3);
 +      cairo_fill(cr);
 +  }
 +
 +  cairo_destroy(cr);
 +}
 +
 +
 +static void
 +gtk_cpu_destroy(GtkObject *object)
 +{
 +  GtkCpu *cpu;
 +  GtkCpuClass *klass;
 +
 +  g_return_if_fail(object != NULL);
 +  g_return_if_fail(GTK_IS_CPU(object));
 +
 +  cpu = GTK_CPU(object);
 +
 +  klass = gtk_type_class(gtk_widget_get_type());
 +
 +  if (GTK_OBJECT_CLASS(klass)->destroy) {
 +     (* GTK_OBJECT_CLASS(klass)->destroy) (object);
 +  }
 +}
 +</code>
 +
 +<code cpp>
 +/* main.c */
 +
 +#include "cpu.h"
 +
 +
 +static void set_value(GtkWidget * widget, gpointer data)
 +{
 +  GdkRegion *region;
 +
 +  GtkRange *range = (GtkRange *) widget;
 +  GtkWidget *cpu = (GtkWidget *) data;
 +  GTK_CPU(cpu)->sel = gtk_range_get_value(range);
 +
 +  region = gdk_drawable_get_clip_region(cpu->window);
 +  gdk_window_invalidate_region(cpu->window, region, TRUE);
 +  gdk_window_process_updates(cpu->window, TRUE);
 +}
 +
 +
 +int main (int argc, char ** argv)
 +{
 +  GtkWidget *window;
 +  GtkWidget *cpu;
 +  GtkWidget *fixed;
 +  GtkWidget *scale;
 +
 +  gtk_init(&argc, &argv);
 +
 +
 +  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +  gtk_window_set_title(GTK_WINDOW(window), "CPU widget");
 +  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 +  gtk_window_set_default_size(GTK_WINDOW(window), 200, 180);
 +
 +
 +  g_signal_connect(G_OBJECT(window), "destroy", 
 +       G_CALLBACK(gtk_main_quit), NULL);
 +
 +  fixed = gtk_fixed_new();
 +  gtk_container_add(GTK_CONTAINER(window), fixed);
 +
 +  cpu = gtk_cpu_new();
 +  gtk_fixed_put(GTK_FIXED(fixed), cpu, 30, 40);
 +
 +
 +  scale = gtk_vscale_new_with_range(0.0, 100.0, 1.0);
 +  gtk_range_set_inverted(GTK_RANGE(scale), TRUE);
 +  gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
 +  gtk_widget_set_size_request(scale, 50, 120);
 +  gtk_fixed_put(GTK_FIXED(fixed), scale, 130, 20);
 +
 +  g_signal_connect(G_OBJECT(scale), "value_changed", G_CALLBACK(set_value), (gpointer) cpu);
 +
 +  gtk_widget_show(cpu);
 +  gtk_widget_show(fixed);
 +  gtk_widget_show_all(window);
 +  gtk_main();
 +
 +  return 0;
 +}
 +</code>
 + ‪  ‪  ‪ 
 +   ودجت ال CPU هو **GtkWidget** اللذى سنرسمه من خلال كايرو، نرسم خلفية سوداء و 40 مستطيل، هذه المستطيلات ترسم بلونين الأخضر الغامق والفاقع
 +   وودجت **GtkVScale** يتحكم عدد المستطيلات الفاقعة المرسومة على الودجت
 +   
 +   المثال ربما يبدو صعبا من الوهلة الأولى، ولكنه ليس صعبا على الإطلاق.
 +   معظم هذه الأكواد نمطى ومتكرر عند انشاء اى ويدجت جديد.
 +   يتم الرسم فى الدالة **gtk_cpu_paint()**
 +    ‬  ‬  ‬ 
 +
 +
 +<code cpp>
 +  cairo_t *cr;
 +
 +  cr = gdk_cairo_create(widget->window);
 +
 +  cairo_translate(cr, 0, 7);
 +
 +  cairo_set_source_rgb(cr, 0, 0, 0);
 +  cairo_paint(cr);
 +</code>
 +
 +
 +
 +كالمعتاد، ننشئ سياق كايرو ونزيج نقطة الأصل 7 وحدات ونقوم برسم الخلفية باللون الأسود.
 +
 +
 +
 +<code cpp>
 + gint pos = GTK_CPU(widget)->sel;
 + gint rect = pos / 5;
 +</code>
 +
 +
 +هنا نحصل على sel -الرقم الذى حصلنا عليه من ويدجت المقياس -scale- 
 +المنزلق يحوى 100 رقم والمعامل rect يقوم بالتحويل من قيم المنزلق الى المستطيل -يتم رسمها بالأخضر الفاقع-
 +
 +
 +
 +<code cpp>
 + gint i;
 + for ( i = 1; i <= 20; i++) {
 +     if (i > 20 - rect) {
 +         cairo_set_source_rgb(cr, 0.6, 1.0, 0);
 +     } else {
 +         cairo_set_source_rgb(cr, 0.2, 0.4, 0);
 +     }
 +     cairo_rectangle(cr, 8, i*4, 30, 3);
 +     cairo_rectangle(cr, 42, i*4, 30, 3);
 +     cairo_fill(cr);
 + }
 +</code>
 +
 +
 +بناءا على رقم ال rect نرسم 40 مستطيل باللونين الأخضر الغامق والفاقع، تذكر اننا نقوم برسم هذه المستطيلات من اعلى لأسفل.
 +
 +
 +
 +<code cpp>
 + GtkRange *range = (GtkRange *) widget;
 + GtkWidget *cpu = (GtkWidget *) data;
 + GTK_CPU(cpu)->sel = gtk_range_get_value(range);
 +</code>
 +
 +
 +استدعاء الدالة **set_value** نحصل على مرجع -reference - لويدجت ال CPU ونحدد قيمة "sel" للقيمة الحالية -المختارة على ويدجت المقياس-.
 +
 +
 +
 +
 +<code cpp>
 + GdkRegion *region;
 + ...
 + region = gdk_drawable_get_clip_region(cpu->window);
 + gdk_window_invalidate_region(cpu->window, region, TRUE);
 + gdk_window_process_updates(cpu->window, TRUE);
 +</code>
 +
 +هذا الكود يلغى مفعولة النافذة لويدجت ال CPU فقتوم بإعادة رسم نفسها.
 +
 +
 +{{ http://zetcode.com/tutorials/cairographicstutorial/images/cpuwidget.png |cpu widget}}
 +
 +
 +
 +
 +
 +
 +
 +
  

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki