Static Data Members

One way to avoid global variables such as appeared in my previous article is to use static data members.

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();
protected:
  virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);
  virtual bool on_button_press_event  ( GdkEventButton* event );
  virtual bool on_button_release_event( GdkEventButton* event );
public:
  static double x_min;
  static double x_max;
  static double y_min;
  static double y_max;
private:
  double x_press;
  double y_press;
  double x_release;
  double y_release;
};
double MyArea::x_min {-1.5};
double MyArea::x_max { 0.5};
double MyArea::y_min {-1.0};
double MyArea::y_max { 1.0};

MyArea::MyArea() : x_press {0.0}, y_press {0.0}, x_release {0.0}, y_release {0.0}
{
	add_events( Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK );
}
void MyButton::on_button1_clicked() {
	double xc = (MyArea::x_min + MyArea::x_max) / 2.0;
	double yc = (MyArea::y_min + MyArea::y_max) / 2.0;
	double xs = (MyArea::x_max - xc) * 0.67;
	double ys = (MyArea::y_max - yc) * 0.67;
	MyArea::x_min = xc - xs;
	MyArea::x_max = xc + xs;
	MyArea::y_min = yc - ys;
	MyArea::y_max = yc + ys;
	get_window()->invalidate(true);
}

I do not know if this is any improvement.

Mouse Events

mouse1

Now you can zoom in to the area you have specified with your mouse.

MyArea: width = 400, height = 400, (-1.5, -1) ----> (0.5, 1) 
pressed:  46.2161 : 126.588
released: 87.2161 : 162.588
MyArea: width = 400, height = 400, (-1.26892, -0.367061) ----> (-1.06392, -0.187061) 

The size of the drawing area is 400 by 400 pixels, and the upper left corner is initially mapped to (xmin=-1.5, ymin=-1), while the lower right corner to (xmax=0.5, ymax=1).

By detectiong the points where the mouse is pressed and released, a new drawing area is defined considering the two points as a diagonal.

bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
  Gtk::Allocation allocation = get_allocation();
  const int width  = allocation.get_width();
  const int height = allocation.get_height();
  if(x_press != x_release && y_press != y_release) {
	  double x_min_new = x_min + (x_max - x_min) * ( x_press   / (double) width );
	  double x_max_new = x_min + (x_max - x_min) * ( x_release / (double) width );
	  x_min = x_min_new;
	  x_max = x_max_new;
	  double y_min_new = y_min + (y_max - y_min) * ( y_press   / (double) height );
	  double y_max_new = y_min + (y_max - y_min) * ( y_release / (double) height );
	  y_min = y_min_new;
	  y_max = y_max_new;
	  x_press = y_press = x_release = y_release = 0.0;
  }
  cout << "MyArea: width = " << width << ", height = " << height
       << ", (" << x_min << ", " << y_min << ") ----> (" << x_max << ", " << y_max << ") \n";
  /*** etc. ***/
}
MyWindow::MyWindow() : m_box(Gtk::ORIENTATION_VERTICAL) {
	add_events( Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK );
  /*** etc. ***/
}

bool MyWindow::on_button_press_event( GdkEventButton* event )
{
    std::cout << "pressed:  " << event->x << " : " << event->y << std::endl;
    x_press = event->x;
    y_press = event->y;
    return true;
}

bool MyWindow::on_button_release_event( GdkEventButton* event )
{
    std::cout << "released: " << event->x << " : " << event->y << std::endl;
    x_release = event->x;
    y_release = event->y;
	get_window()->invalidate(true);
    return true;
}
class MyWindow : public Gtk::Window {
public:
	virtual bool on_button_press_event  ( GdkEventButton* event );
	virtual bool on_button_release_event( GdkEventButton* event );
/*** etc. ***/
};