modern-gtk2: Use Cairo for drawing the partition resizer (!17)

GdkGC has been deprecated in the underlying C / GTK+ 2.22 library.  It
is less clearly stated but Gdk::GC is also deprecated in C++ / gtkmm.
Cairo based rendering should be used instead.
https://developer.gnome.org/gtk3/stable/gtk-migrating-2-to-3.html
https://gitlab.gnome.org/GNOME/gtk/blob/2.22.0/NEWS#L124
https://developer.gnome.org/gtkmm/2.24/classGdk_1_1GC.html

First commit in a series to convert Gdk::GC based drawing to Cairo based
drawing.  This specific commit makes the transition for the graphical
partition resizing widget that is used in the "Create New Partition",
"Paste" creating new partition and "Resize/Move" dialogs.

Cairo is not pixel based but instead uses a continuous coordinate space.
To draw in a pixel aligned way follow the guidance in the Cairo FAQ.
https://www.cairographics.org/FAQ/#sharp_lines

Additional references:
https://developer.gnome.org/gdk2/stable/gdk2-Drawing-Primitives.html#gdk-draw-line
https://developer.gnome.org/gdk2/stable/gdk2-Drawing-Primitives.html#gdk-draw-rectangle

Closes !17 - Gtk2 modernisation
This commit is contained in:
Luca Bacci 2018-08-02 18:10:11 +02:00 committed by Mike Fleetwood
parent c602170faa
commit d17d129044
6 changed files with 132 additions and 112 deletions

View file

@ -47,7 +47,9 @@ public:
int get_x_start() ;
int get_x_end() ;
virtual void Draw_Partition() ;
virtual void draw_partition(const Cairo::RefPtr<Cairo::Context>& cr);
void redraw();
//public signals (emitted upon resize/move)
sigc::signal<void,int,int, ArrowType> signal_resize;
@ -66,13 +68,10 @@ protected:
bool drawingarea_on_button_press_event( GdkEventButton * ev ) ;
bool drawingarea_on_button_release_event( GdkEventButton * ev ) ;
bool drawingarea_on_leave_notify( GdkEventCrossing * ev ) ;
void Draw_Resize_Grip( ArrowType ) ;
void draw_resize_grip(const Cairo::RefPtr<Cairo::Context>& cr, ArrowType);
Gtk::DrawingArea drawingarea ;
Glib::RefPtr<Gdk::GC> gc_drawingarea ;
Glib::RefPtr<Gdk::Pixmap> pixmap ;
Glib::RefPtr<Gdk::GC> gc_pixmap ;
Gdk::Color color_used, color_unused, color_arrow, color_background, color_partition, color_arrow_rectangle;

View file

@ -33,7 +33,7 @@ private:
//overridden signal handler
virtual bool drawingarea_on_mouse_motion( GdkEventMotion * ev ) ;
virtual void Draw_Partition() ;
virtual void draw_partition(const Cairo::RefPtr<Cairo::Context>& cr);
};
#endif /* GPARTED_FRAME_RESIZER_EXTENDED_H */

View file

@ -372,9 +372,9 @@ void Dialog_Base_Partition::on_spinbutton_value_changed( SPINBUTTON spinbutton )
frame_resizer_base ->set_x_start( Utils::round( spinbutton_before .get_value() / MB_PER_PIXEL ) ) ;
frame_resizer_base ->set_x_end( 500 - Utils::round( spinbutton_after .get_value() / MB_PER_PIXEL ) ) ;
frame_resizer_base ->Draw_Partition() ;
frame_resizer_base->redraw();
Check_Change() ;
}
}

View file

@ -382,7 +382,7 @@ void Dialog_Partition_New::combobox_changed(bool type)
// Maximum length of the file system label varies according to the selected file system type.
filesystem_label_entry.set_max_length( Utils::get_filesystem_label_maxlength( fs.filesystem ) );
frame_resizer_base ->Draw_Partition() ;
frame_resizer_base->redraw();
}

View file

@ -17,6 +17,9 @@
#include "Frame_Resizer_Base.h"
#include <gdkmm/general.h>
Frame_Resizer_Base::Frame_Resizer_Base()
{
BORDER = 8 ;
@ -45,13 +48,13 @@ void Frame_Resizer_Base::init()
sigc::mem_fun(*this, &Frame_Resizer_Base::drawingarea_on_leave_notify) ) ;
this ->add( drawingarea ) ;
color_used .set( "#F8F8BA" ); this ->get_colormap() ->alloc_color( color_used ) ;
color_unused .set( "white" ); this ->get_colormap() ->alloc_color( color_unused ) ;
color_arrow .set( "black" ); this ->get_colormap() ->alloc_color( color_arrow ) ;
color_background .set( "darkgrey" ); this ->get_colormap() ->alloc_color( color_background ) ;
color_arrow_rectangle .set( "lightgrey" ); this ->get_colormap() ->alloc_color( color_arrow_rectangle ) ;
color_used.set("#F8F8BA");
color_unused.set("white");
color_arrow.set("black");
color_background.set("darkgrey");
color_arrow_rectangle.set("lightgrey");
cursor_resize = new Gdk::Cursor( Gdk::SB_H_DOUBLE_ARROW ) ;
cursor_move = new Gdk::Cursor( Gdk::FLEUR ) ;
@ -69,16 +72,12 @@ void Frame_Resizer_Base::init()
void Frame_Resizer_Base::set_rgb_partition_color( const Gdk::Color & color )
{
this ->get_colormap() ->free_color( color_partition ) ;
this ->color_partition = color ;
this ->get_colormap() ->alloc_color( color_partition ) ;
}
void Frame_Resizer_Base::override_default_rgb_unused_color( const Gdk::Color & color )
{
this ->get_colormap() ->free_color( color_unused ) ;
this ->color_unused = color ;
this ->get_colormap() ->alloc_color( color_unused ) ;
}
void Frame_Resizer_Base::set_x_start( int x_start )
@ -129,12 +128,6 @@ int Frame_Resizer_Base::get_x_end()
void Frame_Resizer_Base::drawingarea_on_realize()
{
gc_drawingarea = Gdk::GC::create( drawingarea .get_window() );
pixmap = Gdk::Pixmap::create( drawingarea .get_window(),
drawingarea .get_allocation() .get_width(),
drawingarea .get_allocation() .get_height() );
gc_pixmap = Gdk::GC::create( pixmap );
drawingarea .add_events( Gdk::POINTER_MOTION_MASK );
drawingarea .add_events( Gdk::BUTTON_PRESS_MASK );
drawingarea .add_events( Gdk::BUTTON_RELEASE_MASK );
@ -142,8 +135,24 @@ void Frame_Resizer_Base::drawingarea_on_realize()
}
bool Frame_Resizer_Base::drawingarea_on_expose( GdkEventExpose * ev )
{
Draw_Partition() ;
{
Glib::RefPtr<Gdk::Window> window = drawingarea.get_window();
if (!window)
return true;
Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
// Clip to the area indicated by the expose event so that we only redraw
// the portion of the window that needs to be redrawn.
cr->rectangle(ev->area.x, ev->area.y,
ev->area.width, ev->area.height);
cr->clip();
cr->set_line_cap(Cairo::LINE_CAP_SQUARE);
cr->set_line_width(1.0);
draw_partition(cr);
return true;
}
@ -281,8 +290,8 @@ bool Frame_Resizer_Base::drawingarea_on_mouse_motion( GdkEventMotion * ev )
X_START_MOVE = static_cast<int>( ev ->x ) ;
signal_move .emit( X_START - GRIPPER, X_END - GRIPPER - BORDER * 2 ) ;
}
Draw_Partition() ;
redraw();
}
else
{
@ -357,47 +366,49 @@ bool Frame_Resizer_Base::drawingarea_on_leave_notify( GdkEventCrossing *ev )
return true;
}
void Frame_Resizer_Base::Draw_Partition()
void Frame_Resizer_Base::draw_partition(const Cairo::RefPtr<Cairo::Context>& cr)
{
UNUSED = X_END - X_START - BORDER * 2 - USED ;
if ( UNUSED < 0 )
UNUSED = 0 ;
if ( drawingarea .get_window() )
{
//i couldn't find a clear() for a pixmap, that's why ;)
gc_pixmap ->set_foreground( color_background );
pixmap ->draw_rectangle( gc_pixmap, true, 0, 0, 536, 50 );
//the two rectangles on each side of the partition
gc_pixmap ->set_foreground( color_arrow_rectangle );
pixmap ->draw_rectangle( gc_pixmap, true, 0, 0, 10, 50 );
pixmap ->draw_rectangle( gc_pixmap, true, 526, 0, 10, 50 );
//partition
gc_pixmap ->set_foreground( color_partition );
pixmap ->draw_rectangle( gc_pixmap, true, X_START, 0, X_END - X_START, 50 );
//used
gc_pixmap ->set_foreground( color_used );
pixmap ->draw_rectangle( gc_pixmap, true, X_START +BORDER, BORDER, USED, 34 );
//unused
gc_pixmap ->set_foreground( color_unused );
pixmap ->draw_rectangle( gc_pixmap, true, X_START +BORDER +USED, BORDER, UNUSED, 34 );
//resize grips
if ( ! fixed_start )
Draw_Resize_Grip( ARROW_LEFT ) ;
Draw_Resize_Grip( ARROW_RIGHT ) ;
//and draw everything to "real" screen..
drawingarea .get_window() ->draw_drawable( gc_drawingarea, pixmap, 0, 0, 0, 0 ) ;
}
// Background color
Gdk::Cairo::set_source_color(cr, color_background);
cr->rectangle(0, 0, 536, 50);
cr->fill();
// The two rectangles on each side of the partition
Gdk::Cairo::set_source_color(cr, color_arrow_rectangle);
cr->rectangle(0, 0, 10, 50);
cr->fill();
cr->rectangle(526, 0, 10, 50);
cr->fill();
// Partition
Gdk::Cairo::set_source_color(cr, color_partition);
cr->rectangle(X_START, 0, X_END - X_START, 50);
cr->fill();
// Used
Gdk::Cairo::set_source_color(cr, color_used);
cr->rectangle(X_START + BORDER, BORDER, USED, 34);
cr->fill();
// Unused
Gdk::Cairo::set_source_color(cr, color_unused);
cr->rectangle(X_START + BORDER + USED, BORDER, UNUSED, 34);
cr->fill();
// Resize grips
if (!fixed_start)
draw_resize_grip(cr, ARROW_LEFT);
draw_resize_grip(cr, ARROW_RIGHT);
}
void Frame_Resizer_Base::Draw_Resize_Grip( ArrowType arrow_type )
void Frame_Resizer_Base::draw_resize_grip(const Cairo::RefPtr<Cairo::Context>& cr, ArrowType arrow_type)
{
if ( arrow_type == ARROW_LEFT )
{
@ -412,28 +423,30 @@ void Frame_Resizer_Base::Draw_Resize_Grip( ArrowType arrow_type )
arrow_points[ 2 ] .set_x( X_END ) ;
}
//attach resize arrows to the partition
gc_pixmap ->set_foreground( color_arrow_rectangle );
pixmap ->draw_rectangle( gc_pixmap,
false,
arrow_type == ARROW_LEFT ? X_START - GRIPPER : X_END +1,
5,
9,
40 ) ;
gc_pixmap ->set_foreground( color_arrow );
pixmap ->draw_polygon( gc_pixmap, true, arrow_points );
// Attach resize arrows to the partition
Gdk::Cairo::set_source_color(cr, color_arrow_rectangle);
cr->rectangle((arrow_type == ARROW_LEFT ? X_START - GRIPPER : X_END + 1) + 0.5,
5 + 0.5,
9,
40);
cr->stroke();
Gdk::Cairo::set_source_color(cr, color_arrow);
cr->move_to(arrow_points[0].get_x(), arrow_points[0].get_y());
cr->line_to(arrow_points[1].get_x(), arrow_points[1].get_y());
cr->line_to(arrow_points[2].get_x(), arrow_points[2].get_y());
cr->close_path();
cr->fill();
}
void Frame_Resizer_Base::redraw()
{
drawingarea.queue_draw();
}
Frame_Resizer_Base::~Frame_Resizer_Base()
{
this ->get_colormap() ->free_color( color_used ) ;
this ->get_colormap() ->free_color( color_unused ) ;
this ->get_colormap() ->free_color( color_arrow ) ;
this ->get_colormap() ->free_color( color_background ) ;
this ->get_colormap() ->free_color( color_partition ) ;
this ->get_colormap() ->free_color( color_arrow_rectangle ) ;
{
delete cursor_resize;
delete cursor_move;
}

View file

@ -17,6 +17,9 @@
#include "Frame_Resizer_Extended.h"
#include <gdkmm/general.h>
Frame_Resizer_Extended::Frame_Resizer_Extended()
{
}
@ -123,8 +126,8 @@ bool Frame_Resizer_Extended::drawingarea_on_mouse_motion( GdkEventMotion * ev )
}
}
}
Draw_Partition() ;
redraw();
}
//check if pointer is over a gripper
@ -151,30 +154,35 @@ bool Frame_Resizer_Extended::drawingarea_on_mouse_motion( GdkEventMotion * ev )
return true ;
}
void Frame_Resizer_Extended::Draw_Partition()
void Frame_Resizer_Extended::draw_partition(const Cairo::RefPtr<Cairo::Context>& cr)
{
//i couldn't find a clear() for a pixmap, that's why ;)
gc_pixmap ->set_foreground( color_background );
pixmap ->draw_rectangle( gc_pixmap, true, 0, 0, 536, 50 );
//the two rectangles on each side of the partition
gc_pixmap ->set_foreground( color_arrow_rectangle );
pixmap ->draw_rectangle( gc_pixmap, true, 0, 0, 10, 50 );
pixmap ->draw_rectangle( gc_pixmap, true, 526, 0, 10, 50 );
//used
gc_pixmap ->set_foreground( color_used );
pixmap ->draw_rectangle( gc_pixmap, true, USED_START + BORDER, BORDER, USED, 34 );
//partition
gc_pixmap ->set_foreground( color_partition );
// Background color
Gdk::Cairo::set_source_color(cr, color_background);
cr->rectangle(0, 0, 536, 50);
cr->fill();
// The two rectangles on each side of the partition
Gdk::Cairo::set_source_color(cr, color_arrow_rectangle);
cr->rectangle(0, 0, 10, 50);
cr->fill();
cr->rectangle(526, 0, 10, 50);
cr->fill();
// Used
Gdk::Cairo::set_source_color(cr, color_used);
cr->rectangle(USED_START + BORDER, BORDER, USED, 34);
cr->fill();
// Partition
Gdk::Cairo::set_source_color(cr, color_partition);
for( short t = 0; t < 9 ; t++ )
pixmap ->draw_rectangle( gc_pixmap, false, X_START +t, t, X_END - X_START -t*2, 50 - t*2 );
//resize grips
Draw_Resize_Grip( ARROW_LEFT ) ;
Draw_Resize_Grip( ARROW_RIGHT ) ;
//and draw everything to "real" screen..
drawingarea .get_window() ->draw_drawable( gc_drawingarea, pixmap, 0, 0, 0, 0 ) ;
{
cr->rectangle(X_START + t + 0.5, t + 0.5, X_END - X_START - t*2, 50 - t*2);
cr->stroke();
}
// Resize grips
draw_resize_grip(cr, ARROW_LEFT);
draw_resize_grip(cr, ARROW_RIGHT);
}