- cairo_widget.cc - documentation completed, removed all warnings

- simulation_widget.hh - documentation completed



git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@1164 3ecf2c5c-341e-0410-92b4-d18e462d057c
This commit is contained in:
paolo 2006-09-14 22:31:37 +00:00
parent bb74bcbc48
commit bd6e52f811
2 changed files with 256 additions and 50 deletions

View File

@ -27,7 +27,6 @@
#include <cassert> #include <cassert>
#include <iostream>
#include <memory> #include <memory>
using namespace sgpem; using namespace sgpem;
@ -36,9 +35,10 @@ using namespace sgpem;
CairoWidget::CairoWidget() CairoWidget::CairoWidget()
: Glib::ObjectBase("sgpem_CairoWidget"), : Glib::ObjectBase("sgpem_CairoWidget"),
Gtk::Widget(), Gtk::Widget(),
_draw_w(1), _draw_h(1), _buf(NULL), _draw_w(1), _draw_h(1),
_client_w(0), _client_h(0), _pixmap_w(0), _pixmap_h(0), _client_w(0), _client_h(0), _pixmap_w(0), _pixmap_h(0),
_need_redraw(true), _scaling_mode(scaling_none) _need_redraw(true), _scaling_mode(scaling_none),
_buf(NULL)
{ {
set_flags(Gtk::NO_WINDOW); set_flags(Gtk::NO_WINDOW);
} }
@ -48,6 +48,9 @@ CairoWidget::~CairoWidget()
{ {
} }
/*
Scaling mode setter+getter method.
*/
CairoWidget::scaling_mode CairoWidget::scaling_mode
CairoWidget::set_scaling_mode(CairoWidget::scaling_mode scaling) CairoWidget::set_scaling_mode(CairoWidget::scaling_mode scaling)
{ {
@ -56,16 +59,22 @@ CairoWidget::set_scaling_mode(CairoWidget::scaling_mode scaling)
return old_scaling; return old_scaling;
} }
/*
Scaling mode getter method.
*/
CairoWidget::scaling_mode CairoWidget::scaling_mode
CairoWidget::get_scaling_mode() const CairoWidget::get_scaling_mode() const
{ {
return _scaling_mode; return _scaling_mode;
} }
/*
Called by Gtk+ before creting the widget.
Sets all values and attributes required.
*/
void void
CairoWidget::on_realize() CairoWidget::on_realize()
{ {
// std::cout << " on_realize" << std::endl;
if (is_realized()) return; if (is_realized()) return;
Gtk::Widget::on_realize(); Gtk::Widget::on_realize();
@ -89,7 +98,6 @@ CairoWidget::on_realize()
_client_w = alloc.get_width(); _client_w = alloc.get_width();
_client_h = alloc.get_height(); _client_h = alloc.get_height();
// std::cout << " on_realize, alloc.get_width() : " << alloc.get_width() << ", alloc.get_height() : " << alloc.get_height() << std::endl;
static const gint attributes_mask = Gdk::WA_X | Gdk::WA_Y | Gdk::WA_WMCLASS static const gint attributes_mask = Gdk::WA_X | Gdk::WA_Y | Gdk::WA_WMCLASS
| Gdk::WA_VISUAL | Gdk::WA_COLORMAP; | Gdk::WA_VISUAL | Gdk::WA_COLORMAP;
@ -107,66 +115,85 @@ CairoWidget::on_realize()
get_style()->set_background(window, Gtk::STATE_ACTIVE); get_style()->set_background(window, Gtk::STATE_ACTIVE);
} }
/*
This method is called when the widget is moved/resized.
*/
void void
CairoWidget::on_size_allocate(const Gtk::Allocation& allocation) CairoWidget::on_size_allocate(const Gtk::Allocation& allocation)
{ {
// std::cout << " on_size_allocate, allocation.get_width() : " << allocation.get_width() << ", allocation.get_height() : " << allocation.get_height() << std::endl;
set_allocation(allocation); set_allocation(allocation);
if (is_realized()) if (is_realized())
{ {
get_window()->move_resize(allocation.get_x(), allocation.get_y(), get_window()->move_resize(allocation.get_x(), allocation.get_y(),
allocation.get_width(), allocation.get_height()); allocation.get_width(), allocation.get_height());
// the widget's dimension are saved for futher use
_client_w = allocation.get_width(); _client_w = allocation.get_width();
_client_h = allocation.get_height(); _client_h = allocation.get_height();
// the widget must be redrawn
_need_redraw = true; _need_redraw = true;
} }
} }
/*
This method is called by Gtk to get the widget desired size.
*/
void void
CairoWidget::on_size_request(Gtk::Requisition* requisition) CairoWidget::on_size_request(Gtk::Requisition* requisition)
{ {
// Gtk+ asks the desired widget dimension // gets the passed values
// std::cout << " on_size_request, requisition->width : " << requisition->width << ", requisition->height : " << requisition->height << std::endl;
_client_w = requisition->width; _client_w = requisition->width;
_client_h = requisition->height; _client_h = requisition->height;
// ask the desired dimensions
calc_widget_size(_client_w, _client_h); calc_widget_size(_client_w, _client_h);
// pass values back to Gtk
requisition->width = _client_w; requisition->width = _client_w;
requisition->height = _client_h; requisition->height = _client_h;
} }
/*
This method is called by Gtk when need to redraw widget
*/
bool bool
CairoWidget::on_expose_event(GdkEventExpose* event) CairoWidget::on_expose_event(GdkEventExpose* event)
{ {
// std::cout << " on_expose_event START...";
if (event == NULL || event->count > 0) if (event == NULL || event->count > 0)
return false; return false;
// std::cout << " on_expose_event CONTINUE." << std::endl;
int actual_w = get_width(); // save actual size
int actual_h = get_height(); size_t actual_w = get_width();
// std::cout << " get_width() : " << actual_w << ", get_height() : " << actual_h << std::endl; size_t actual_h = get_height();
// std::cout << " _client_w : " << _client_w << ", _client_h : " << _client_h << std::endl;
// std::cout << " _pixmap_w : " << _pixmap_w << ", _pixmap_h : " << _pixmap_h << std::endl;
// the widget must be redrawn if
// - there's an explicit request(_need_redraw)
// - the size is changed
if(_need_redraw || actual_w!=_client_w || actual_h!=_client_h) if(_need_redraw || actual_w!=_client_w || actual_h!=_client_h)
{ {
// reset flag, set values with actual size
_need_redraw = false; _need_redraw = false;
_client_w = actual_w; _client_w = actual_w;
_client_h = actual_h; _client_h = actual_h;
// lazy technique: allocate only if growing...
// The pixmap must be crated or no?
// If the pixmap buffer size isn't enough
// it must be allocated or reallocated.
// Here is used a lazy technique:
// allocate only if growing, keep if shrinking.
// Taking a bigger pixmap saves operations when
// many window resizing occours (i.e. mouse resizing).
if(_client_w>_pixmap_w || _client_h>_pixmap_h) if(_client_w>_pixmap_w || _client_h>_pixmap_h)
{ {
// previdence in the code: allocate more than actually needed // previdence in the code:
// allocate more than actually needed
_pixmap_w = (size_t) (_client_w*1.2); _pixmap_w = (size_t) (_client_w*1.2);
_pixmap_h = (size_t) (_client_h*1.2); _pixmap_h = (size_t) (_client_h*1.2);
// std::cout << " on_expose_event CREATE Pixmap. w : " << _pixmap_w << ", h : " << _pixmap_h<< std::endl;
// allocate the pixmap
_buf = Gdk::Pixmap::create(get_window(), _pixmap_w, _pixmap_h); _buf = Gdk::Pixmap::create(get_window(), _pixmap_w, _pixmap_h);
} }
@ -175,30 +202,31 @@ CairoWidget::on_expose_event(GdkEventExpose* event)
// I've seen this is how it's done in the very Gtk+ toolkit // I've seen this is how it's done in the very Gtk+ toolkit
// for the GtkProgressBar widget. // for the GtkProgressBar widget.
GtkStyle* gStyle = get_style()->gobj(); GtkStyle* gStyle = get_style()->gobj();
// std::cout << " on_expose_event gtk_paint_box." << std::endl;
gtk_paint_box(gStyle, _buf->gobj(), gtk_paint_box(gStyle, _buf->gobj(),
GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_IN, GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_IN,
NULL, (GtkWidget*)this->gobj(), "through", NULL, (GtkWidget*)this->gobj(), "through",
0, 0, _client_w, _client_h); 0, 0, _client_w, _client_h);
// here the cairo context is creted
cairo_t* ctx = gdk_cairo_create(_buf->gobj()); cairo_t* ctx = gdk_cairo_create(_buf->gobj());
// Determine the final drawing dimensions before to start drawing // Determine the final drawing dimensions
// before to start drawing
_draw_w = _draw_h = 0; // default no scaling _draw_w = _draw_h = 0; // default no scaling
calc_drawing_size(ctx, _draw_w, _draw_h); calc_drawing_size(ctx, _draw_w, _draw_h);
// calculate and apply scale factors
calc_scale_factors(); calc_scale_factors();
// do the drawing...
cairo_scale(ctx, _scale_x, _scale_y); cairo_scale(ctx, _scale_x, _scale_y);
// std::cout << " on_expose_event Dimensions, w : " << _draw_w << ", h : " << _draw_h << std::endl; // do the drawing...
draw_widget(ctx); draw_widget(ctx);
cairo_destroy(ctx);
}
// calculated dinamically on update(): // bye bye context
// set_size_request(_draw_w, _draw_h); cairo_destroy(ctx);
} // ~ if(_need_redraw || actual_w!=_client_w || actual_h!=_client_h)
// Now the in-memory picture is placed on screen
// Clip to redraw only the smallest possible area // Clip to redraw only the smallest possible area
// Use double buffering or we're CPU-dead // Use double buffering or we're CPU-dead
@ -212,61 +240,98 @@ CairoWidget::on_expose_event(GdkEventExpose* event)
return true; return true;
} }
/*
Here calc the scale factors to apply drawing
*/
void void
CairoWidget::calc_scale_factors() CairoWidget::calc_scale_factors()
{ {
// scale factor is: desired_size/effective_size
//
// "desired_size" here is how big can fin in window
// "effective_size" is how big the application produce
if(_scaling_mode!=scaling_none && _draw_w!=0 && _draw_h!=0) if(_scaling_mode!=scaling_none && _draw_w!=0 && _draw_h!=0)
{ {
// there are two possible scale factors x and y
_scale_x = (double)_client_w/(double)_draw_w; _scale_x = (double)_client_w/(double)_draw_w;
_scale_y = (double)_client_h/(double)_draw_h; _scale_y = (double)_client_h/(double)_draw_h;
// will be chosen one, another, both or none
// depending on the active mode
switch(_scaling_mode) switch(_scaling_mode)
{ {
case scaling_none: // not necessary! case scaling_none: // not necessary!
// doesn't scale
_scale_x = _scale_y = 1.0; _scale_x = _scale_y = 1.0;
break; break;
case scaling_to_w: case scaling_to_w:
// scale to fit in width
// x and y take the same x value
_scale_y = _scale_x; _scale_y = _scale_x;
break; break;
case scaling_to_h: case scaling_to_h:
// scale to fit in height
// x and y take the same y value
_scale_x = _scale_y; _scale_x = _scale_y;
break; break;
case scaling_min: case scaling_min:
// scale to fit always in window
// x and y take the same minimum value
if(_scale_x<=_scale_y) if(_scale_x<=_scale_y)
_scale_y = _scale_x; _scale_y = _scale_x;
else else
_scale_x = _scale_y; _scale_x = _scale_y;
break; break;
case scaling_max: case scaling_max:
// scale to fit never in window
// x and y take the same mxiimum value
if(_scale_x>=_scale_y) if(_scale_x>=_scale_y)
_scale_y = _scale_x; _scale_y = _scale_x;
else else
_scale_x = _scale_y; _scale_x = _scale_y;
break; break;
case scaling_all: case scaling_all:
// scale to fit stretching in window
// x and y mantain the differnt calculated values
//
// nothing to do... // nothing to do...
break; break;
} }
} }
else else
{ {
// can't determine scaling factors:
// take the easy way
_scale_x = _scale_y = 1.0; _scale_x = _scale_y = 1.0;
} }
} }
/*
Utility method: force to redraw widget
*/
void void
CairoWidget::redraw() CairoWidget::redraw()
{ {
// Force redraw // Force redraw
_need_redraw = true; _need_redraw = true;
// invalidate all widget's surface
queue_draw(); queue_draw();
} }
/*
Utility method: force to resize and redraw widget
*/
void void
CairoWidget::resize_redraw() CairoWidget::resize_redraw()
{ {
// Force redraw
_need_redraw = true;
// std::cout << " resize_redraw BEGIN width: " << get_width() << ", height: " << get_height() << std::endl;
if(_buf) if(_buf)
{ {
cairo_t* ctx = gdk_cairo_create(_buf->gobj()); cairo_t* ctx = gdk_cairo_create(_buf->gobj());
@ -281,23 +346,29 @@ CairoWidget::resize_redraw()
set_size_request((int)_scale_x*_draw_w, (int)_scale_y*_draw_h); set_size_request((int)_scale_x*_draw_w, (int)_scale_y*_draw_h);
cairo_destroy(ctx); cairo_destroy(ctx);
//std::cout << " resize_redraw DO width: " << _scale_x*_draw_w << ", height: " << _scale_y*_draw_h << std::endl;
} }
} }
// Force redraw // invalidate all widget's surface
_need_redraw = true;
queue_draw(); queue_draw();
} }
/*
Dummy method.
Derived classes can reimplement it or not as desired.
*/
void void
CairoWidget::calc_drawing_size(cairo_t* ctx, size_t& width, size_t& height) CairoWidget::calc_drawing_size(cairo_t* /* ctx */, size_t& /* width */, size_t& /*height*/)
{ {
} }
/*
Dummy method.
Derived classes can reimplement it or not as desired.
*/
void void
CairoWidget::calc_widget_size(size_t& width, size_t& height) CairoWidget::calc_widget_size(size_t& /*width*/, size_t& /*height*/)
{ {
} }

View File

@ -30,60 +30,184 @@
namespace sgpem namespace sgpem
{ {
class SimulationWidget : public SimulationObserver, public HistoryObserver, public CairoWidget /**
* \brief Implements a cairo widget to draw the simulation
* processes ststus graphical rapresentation.
*
* It shows the simulation processes (and threads if flag is enabled)
* names on the left and a bar for each of these on the right.
* The bar begins at the time the process bring to life and ends
* when it die.
*
* The bar is composed of small rectangles of different colors
* depending on the process' status:
* - green = running
* - yellow = ready
* - red = blocked
* This is the Fantasy Kingdom, do you know? ;)
*
* At the bottom of the graph there is a time line ruler.
*
* This class implemets a SimulationObserver and HistoryObserver
* to have an update signal (and related update) every simulation step.
*
* \deprecated The class should implement only HistoryObserver
*
* \see SimulationObserver
* \see HistoryObserver
*/
class SimulationWidget
: public SimulationObserver, public HistoryObserver, public CairoWidget
{ {
public: public:
/**
* \brief default and unique constructor.
*
* Saves the passed argument in data member _simulation.
*/
SimulationWidget(Simulation& simulation); SimulationWidget(Simulation& simulation);
/**
* Destructor!
*/
virtual ~SimulationWidget(); virtual ~SimulationWidget();
/**
* \brief SimulationObserver's update method redefinition.
*
* Actually is a dummy method.
*/
virtual void update(const Simulation& changed_simulation); virtual void update(const Simulation& changed_simulation);
/**
* \brief HistoryObserver's update method redefinition.
*
* Updates the widget to reflects history current state.
*/
virtual void update(const History& changed_history); virtual void update(const History& changed_history);
/**
* \brief Gets the _show_threads flag current status.
*/
bool get_show_threads(); bool get_show_threads();
/**
* \brief Sets gets the _show_threads flag status.
*
* If _show_threads is enabled both processes and threads
* will be drawn on widget.
* If _show_threads is disabled only processes
* will be shown.
*/
bool set_show_threads(bool show); bool set_show_threads(bool show);
protected: protected:
/**
* \brief Catches the mouse click to show a "scaling options"
* popup menu.
*/
virtual bool on_button_press_event(GdkEventButton* event); virtual bool on_button_press_event(GdkEventButton* event);
// void change_scaling_mode();
/**
* \brief Execute the widget painting when needed.
*
* \see CairoWidget() for more.
*/
void draw_widget(cairo_t* ctx); void draw_widget(cairo_t* ctx);
/**
* \brief calculated the needed drawing surface dimensions.
*/
virtual void calc_drawing_size(cairo_t* ctx, size_t& width, size_t& height); virtual void calc_drawing_size(cairo_t* ctx, size_t& width, size_t& height);
void count_elements();
void draw_names(cairo_t* ctx);
void draw_grid(cairo_t* ctx);
void draw_bars(cairo_t* ctx);
void draw_instant_rect(cairo_t* ctx, double x, double y,
double w, double h, sgpem::Schedulable::state state);
void make_gradients();
private: private:
/**
* \brief Counts the processes number to have the final picture size.
*/
void count_elements();
/**
* \brief Used internally by draw_widget to show processes/threads name.
*/
void draw_names(cairo_t* ctx);
/**
* \brief Used internally by draw_widget to show the bars container grid.
*/
void draw_grid(cairo_t* ctx);
/**
* \brief Used internally by draw_widget to show processes/threads bars.
*/
void draw_bars(cairo_t* ctx);
/**
* \brief Used internally by draw_widget to build the bars.
*/
void draw_instant_rect(cairo_t* ctx, double x, double y,
double w, double h, sgpem::Schedulable::state state);
/**
* \brief Build the gradients used to picture the bars.
*
* Gradinets are filling colors soft degrading.
* Please refer to cairo documentetion for more.
*/
void make_gradients();
/**
* \brief "No scaling" menu command responding mathod.
*/
void _on_no_scaling(); void _on_no_scaling();
/**
* \brief "Fit scaling" menu command responding mathod.
*/
void _on_fit_scaling(); void _on_fit_scaling();
/**
* \brief "Stetch scaling" menu command responding mathod.
*/
void _on_stretch_scaling(); void _on_stretch_scaling();
/**
* \brief Pointer to the observed simulation.
*/
Simulation* _simulation; Simulation* _simulation;
/**
* \brief Flag to enable/disable threads visualization.
*/
bool _show_threads; bool _show_threads;
/** /**
drawing x unit * \brief Drawing x unit.
*
* The drawing is constructed upon an arbitrary "squared" surface.
* All widgets drawing measure are defined as upon x and y units.
* To avoid alignement problems the drawing units are evaluated
* on text size. The widtx/height of the text "999" are used as unit.
*/ */
double _x_unit; double _x_unit;
/** /**
drawing y unit * \brief Drawing y unit.
*
* \see _x_unit
*/ */
double _y_unit; double _y_unit;
/** /**
actual number of processes * \brief Actual number of processes, needed by drawing rountines.
*/ */
int _n_proc; int _n_proc;
/** /**
actual number of threads * \brief Actual number of threads, needed by drawing rountines.
*/ */
int _n_thr; int _n_thr;
@ -123,8 +247,19 @@ namespace sgpem
*/ */
double _yu_thread_bar_height; double _yu_thread_bar_height;
/**
* \brief Gradient used to draw ready processes/threads.
*/
cairo_pattern_t* _ready_process_gradient; cairo_pattern_t* _ready_process_gradient;
/**
* \brief Gradient used to draw running processes/threads.
*/
cairo_pattern_t* _running_process_gradient; cairo_pattern_t* _running_process_gradient;
/**
* \brief Gradient used to draw blocked processes/threads.
*/
cairo_pattern_t* _blocked_process_gradient; cairo_pattern_t* _blocked_process_gradient;
/** /**