gparted/src/DrawingAreaVisualDisk.cc

434 lines
13 KiB
C++

/* Copyright (C) 2004 Bart
* Copyright (C) 2010 Curtis Gedak
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "DrawingAreaVisualDisk.h"
#include "Partition.h"
#include "PartitionLUKS.h"
#include "PartitionVector.h"
#include "Utils.h"
#include <gdkmm/general.h>
#define MAIN_BORDER 5
#define BORDER 4
#define SEP 4
#define HEIGHT 70 + 2 * MAIN_BORDER
namespace GParted
{
DrawingAreaVisualDisk::DrawingAreaVisualDisk()
{
selected_vp = nullptr;
// Set some standard colors
color_used.set(Utils::get_color(FS_USED));
color_unused.set(Utils::get_color(FS_UNUSED));
color_unallocated.set(Utils::get_color(FS_UNALLOCATED));
color_text .set( "black" );
add_events( Gdk::BUTTON_PRESS_MASK );
set_size_request( -1, HEIGHT ) ;
}
void DrawingAreaVisualDisk::load_partitions( const PartitionVector & partitions, Sector device_length )
{
clear() ;
TOT_SEP = get_total_separator_px( partitions ) ;
set_static_data( partitions, visual_partitions, device_length ) ;
queue_resize() ;
}
void DrawingAreaVisualDisk::set_selected( const Partition * partition_ptr )
{
selected_vp = nullptr;
set_selected( visual_partitions, partition_ptr );
queue_draw() ;
}
void DrawingAreaVisualDisk::clear()
{
visual_partitions .clear() ;
selected_vp = nullptr;
queue_resize() ;
}
int DrawingAreaVisualDisk::get_total_separator_px( const PartitionVector & partitions )
{
for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
if (partitions[t].type == TYPE_EXTENDED)
return ( partitions[ t ] .logicals .size() -1 + partitions .size() -1 ) * SEP ;
return ( partitions .size() -1 ) * SEP ;
}
void DrawingAreaVisualDisk::set_static_data( const PartitionVector & partitions,
std::vector<visual_partition> & visual_partitions,
Sector length )
{
for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
{
visual_partitions .push_back( visual_partition() ) ;
visual_partitions.back().partition_ptr = & partitions[t];
Sector partition_length = partitions[ t ] .get_sector_length() ;
visual_partitions .back() .fraction = partition_length / static_cast<double>( length ) ;
Glib::ustring color_str = Utils::get_color(partitions[t].get_filesystem_partition().fstype);
visual_partitions.back().color.set( color_str );
if (partitions[t].type == TYPE_EXTENDED)
set_static_data( partitions[t].logicals,
visual_partitions.back().logicals, partition_length );
else
visual_partitions .back() .pango_layout = create_pango_layout(
partitions[ t ] .get_path() + "\n" + Utils::format_size( partition_length, partitions[ t ] .sector_size ) ) ;
}
}
int DrawingAreaVisualDisk::calc_length( std::vector<visual_partition> & visual_partitions, int length_px )
{
int calced_length = 0 ;
for ( int t = 0 ; t < static_cast<int>( visual_partitions .size() ) ; t++ )
{
visual_partitions[ t ] .length = Utils::round( length_px * visual_partitions[ t ] .fraction ) ;
if ( visual_partitions[ t ] .logicals .size() > 0 )
visual_partitions[ t ] .length =
calc_length( visual_partitions[ t ] .logicals,
visual_partitions[ t ] .length - (2 * BORDER) ) + (2 * BORDER) ;
else if ( visual_partitions[ t ] .length < MIN_SIZE )
visual_partitions[ t ] .length = MIN_SIZE ;
calced_length += visual_partitions[ t ] .length ;
}
return calced_length + (visual_partitions .size() - 1) * SEP ;
}
void DrawingAreaVisualDisk::calc_position_and_height( std::vector<visual_partition> & visual_partitions,
int start,
int border )
{
for ( unsigned int t = 0 ; t < visual_partitions .size() ; t++ )
{
visual_partitions[ t ] .x_start = start ;
visual_partitions[ t ] .y_start = border ;
visual_partitions[ t ] .height = HEIGHT - ( border * 2 ) ;
if ( visual_partitions[ t ] .logicals .size() > 0 )
calc_position_and_height( visual_partitions[ t ] .logicals,
visual_partitions[ t ] .x_start + BORDER,
visual_partitions[ t ] .y_start + BORDER ) ;
start += visual_partitions[ t ] .length + SEP ;
}
}
void DrawingAreaVisualDisk::calc_usage( std::vector<visual_partition> & visual_partitions )
{
for ( unsigned int t = 0 ; t < visual_partitions .size() ; t++ )
{
if (visual_partitions[t].partition_ptr->fstype != FS_UNALLOCATED &&
visual_partitions[t].partition_ptr->type != TYPE_EXTENDED )
{
if ( visual_partitions[t].partition_ptr->sector_usage_known() )
{
visual_partitions[t].partition_ptr->get_usage_triple(
visual_partitions[ t ] .length - BORDER *2,
visual_partitions[ t ] .used_length,
visual_partitions[ t ] .unused_length,
visual_partitions[ t ] .unallocated_length ) ;
}
else
{
//Specifically show unknown figures as unused
visual_partitions[ t ] .used_length = 0 ;
visual_partitions[ t ] .unused_length = visual_partitions[ t ] .length - BORDER *2 ;
visual_partitions[ t ] .unallocated_length = 0 ;
}
//used
visual_partitions[ t ] .x_used_start = visual_partitions[ t ] .x_start + BORDER ;
//unused
visual_partitions[ t ] .x_unused_start = visual_partitions[ t ] .x_used_start
+ visual_partitions[ t ] .used_length ;
//unallocated
visual_partitions[ t ] .x_unallocated_start = visual_partitions[ t ] .x_unused_start
+ visual_partitions[ t ] .unused_length ;
//y position and height
visual_partitions[ t ] .y_usage_start = visual_partitions[ t ] .y_start + BORDER ;
visual_partitions[ t ] .usage_height = visual_partitions[ t ] .height - (2 * BORDER) ;
}
if ( visual_partitions[ t ] .logicals .size() > 0 )
calc_usage( visual_partitions[ t ] .logicals ) ;
}
}
void DrawingAreaVisualDisk::calc_text( std::vector<visual_partition> & visual_partitions )
{
int length, height ;
for ( unsigned int t = 0 ; t < visual_partitions .size() ; t++ )
{
if ( visual_partitions[ t ] .pango_layout )
{
//see if the text fits in the partition... (and if so, center the text..)
visual_partitions[ t ] .pango_layout ->get_pixel_size( length, height ) ;
if ( length < visual_partitions[ t ] .length - (2 * BORDER) - 2 )
{
visual_partitions[ t ] .x_text = visual_partitions[ t ] .x_start +
Utils::round( (visual_partitions[ t ] .length / 2) - (length / 2) ) ;
visual_partitions[ t ] .y_text = visual_partitions[ t ] .y_start +
Utils::round( (visual_partitions[ t ] .height / 2) - (height / 2) ) ;
}
else
visual_partitions[ t ] .x_text = visual_partitions[ t ] .y_text = 0 ;
}
if ( visual_partitions[ t ] .logicals .size() > 0 )
calc_text( visual_partitions[ t ] .logicals ) ;
}
}
void DrawingAreaVisualDisk::draw_partition(const Cairo::RefPtr<Cairo::Context>& cr,
const visual_partition& vp)
{
//partition...
Gdk::Cairo::set_source_rgba(cr, vp.color);
cr->rectangle(vp.x_start,
vp.y_start,
vp.length,
vp.height);
cr->fill();
//used..
if ( vp .used_length > 0 )
{
Gdk::Cairo::set_source_rgba(cr, color_used);
cr->rectangle(vp.x_used_start,
vp.y_usage_start,
vp.used_length,
vp.usage_height);
cr->fill();
}
//unused
if ( vp .unused_length > 0 )
{
Gdk::Cairo::set_source_rgba(cr, color_unused);
cr->rectangle(vp.x_unused_start,
vp.y_usage_start,
vp.unused_length,
vp.usage_height);
cr->fill();
}
//unallocated
if ( vp .unallocated_length > 0 )
{
Gdk::Cairo::set_source_rgba(cr, color_unallocated);
cr->rectangle(vp.x_unallocated_start,
vp.y_usage_start,
vp.unallocated_length,
vp.usage_height);
cr->fill();
}
//text
if ( vp .x_text > 0 )
{
Gdk::Cairo::set_source_rgba(cr, color_text);
cr->move_to(vp.x_text, vp.y_text);
vp.pango_layout->show_in_cairo_context(cr);
}
}
void DrawingAreaVisualDisk::draw_partitions(const Cairo::RefPtr<Cairo::Context>& cr,
const std::vector<visual_partition>& visual_partitions)
{
for ( unsigned int t = 0 ; t < visual_partitions .size() ; t++ )
{
draw_partition(cr, visual_partitions[t]);
if ( visual_partitions[ t ] .logicals .size() > 0 )
draw_partitions(cr, visual_partitions[t].logicals);
}
}
void DrawingAreaVisualDisk::set_selected( const std::vector<visual_partition> & visual_partitions, int x, int y )
{
for ( unsigned int t = 0 ; t < visual_partitions .size() && ! selected_vp ; t++ )
{
if ( visual_partitions[ t ] .logicals .size() > 0 )
set_selected( visual_partitions[ t ] .logicals, x, y ) ;
if ( ! selected_vp &&
visual_partitions[ t ] .x_start <= x &&
x < visual_partitions[ t ] .x_start + visual_partitions[ t ] .length &&
visual_partitions[ t ] .y_start <= y &&
y < visual_partitions[ t ] .y_start + visual_partitions[ t ] .height )
{
selected_vp = & visual_partitions[ t ] ;
}
}
}
void DrawingAreaVisualDisk::set_selected( const std::vector<visual_partition> & visual_partitions,
const Partition * partition_ptr )
{
for ( unsigned int t = 0 ; t < visual_partitions .size() && ! selected_vp ; t++ )
{
if ( visual_partitions[ t ] .logicals .size() > 0 )
set_selected( visual_partitions[t].logicals, partition_ptr );
if ( ! selected_vp && *visual_partitions[t].partition_ptr == *partition_ptr )
selected_vp = & visual_partitions[ t ] ;
}
}
bool DrawingAreaVisualDisk::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
bool ret_val = Gtk::DrawingArea::on_draw(cr);
cr->set_line_width(2.0);
cr->set_line_join(Cairo::LINE_JOIN_MITER); // default
cr->set_line_cap(Cairo::LINE_CAP_BUTT); // default
cr->set_dash(std::vector<double>(1, 4.0), 0.0);
draw_partitions(cr, visual_partitions);
//selection
if ( selected_vp )
{
Gdk::Cairo::set_source_rgba(cr, color_used);
cr->rectangle(selected_vp->x_start + BORDER/2,
selected_vp->y_start + BORDER/2,
selected_vp->length - BORDER,
selected_vp->height - BORDER);
cr->stroke();
}
return ret_val ;
}
bool DrawingAreaVisualDisk::on_button_press_event( GdkEventButton * event )
{
bool ret_val = Gtk::DrawingArea::on_button_press_event( event ) ;
selected_vp = nullptr;
set_selected( visual_partitions, static_cast<int>( event ->x ), static_cast<int>( event ->y ) ) ;
queue_draw() ;
if ( selected_vp )
{
signal_partition_selected.emit( selected_vp->partition_ptr, false );
if ( event ->type == GDK_2BUTTON_PRESS )
signal_partition_activated .emit() ;
else if ( event ->button == 3 )
signal_popup_menu .emit( event ->button, event ->time ) ;
}
return ret_val ;
}
void DrawingAreaVisualDisk::on_size_allocate( Gtk::Allocation & allocation )
{
Gtk::DrawingArea::on_size_allocate( allocation ) ;
MIN_SIZE = BORDER * 2 + 2 ;
int available_size = allocation .get_width() - (2 * MAIN_BORDER),
calced = 0,
px_left ;
do
{
px_left = available_size - TOT_SEP ;
calced = available_size ; //for first time :)
do
{
px_left -= ( calced - available_size ) ;
calced = calc_length( visual_partitions, px_left ) ;
}
while ( calced > available_size && px_left > 0 ) ;
MIN_SIZE-- ;
}
while ( px_left <= 0 && MIN_SIZE > 0 ) ;
//due to rounding a few px may be lost. here we salvage them..
if ( visual_partitions .size() && calced > 0 )
{
px_left = available_size - calced ;
while ( px_left > 0 )
px_left = spreadout_leftover_px( visual_partitions, px_left ) ;
}
//and calculate the rest..
calc_position_and_height( visual_partitions, MAIN_BORDER, MAIN_BORDER ) ;//0, 0 ) ;
calc_usage( visual_partitions ) ;
calc_text( visual_partitions ) ;
queue_draw();
}
int DrawingAreaVisualDisk::spreadout_leftover_px( std::vector<visual_partition> & visual_partitions, int pixels )
{
int extended = -1 ;
for ( unsigned int t = 0 ; t < visual_partitions .size() && pixels > 0 ; t++ )
if ( ! visual_partitions[ t ] .logicals .size() )
{
visual_partitions[ t ] .length++ ;
pixels-- ;
}
else
extended = t ;
if ( extended > -1 && pixels > 0 )
{
int actually_used = pixels - spreadout_leftover_px( visual_partitions[ extended ] .logicals, pixels ) ;
visual_partitions[ extended ] .length += actually_used ;
pixels -= actually_used ;
}
return pixels ;
}
DrawingAreaVisualDisk::~DrawingAreaVisualDisk()
{
clear() ;
}
} //GParted