It works, but I am not satisfied.
/* main.cpp */
#include "MyWindow.h"
#include <gtkmm/application.h>
int main(int argc, char** argv)
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
MyWindow win;
return app->run(win);
}
/* MyWindow.h */
#ifndef MYWINDOW_H_
#define MYWINDOW_H_
#include "MyArea.h"
#include <gtkmm/window.h>
#include <gtkmm/box.h>
#include <gtkmm/button.h>
class MyWindow : public Gtk::Window {
public:
MyWindow();
virtual ~MyWindow();
protected:
void on_button1_clicked();
void on_button2_clicked();
void on_button3_clicked();
void on_button4_clicked();
void on_button5_clicked();
void on_button6_clicked();
private:
Gtk::Box m_box;
Gtk::Box m_buttons;
Gtk::Button m_button1;
Gtk::Button m_button2;
Gtk::Button m_button3;
Gtk::Button m_button4;
Gtk::Button m_button5;
Gtk::Button m_button6;
MyArea m_area;
};
#endif /* MYWINDOW_H_ */
/* MyWindow.cpp */
#include "MyWindow.h"
#include "MyArea.h"
MyWindow::MyWindow() : m_box(Gtk::ORIENTATION_VERTICAL), m_buttons(Gtk::ORIENTATION_HORIZONTAL),
m_button1("reset"), m_button2("shrink"), m_button3("left"), m_button4("right"), m_button5("up"), m_button6("down") {
set_title("Not comfortable...");
set_default_size(300, 329);
add(m_box);
m_box.pack_start(m_buttons, false, true);
m_buttons.pack_start(m_button1, true, true);
m_buttons.pack_start(m_button2, true, true);
m_buttons.pack_start(m_button3, true, true);
m_buttons.pack_start(m_button4, true, true);
m_buttons.pack_start(m_button5, true, true);
m_buttons.pack_start(m_button6, true, true);
m_button1.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button1_clicked));
m_button1.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button1_clicked));
m_button1.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button1_clicked));
m_button2.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button2_clicked));
m_button3.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button3_clicked));
m_button4.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button4_clicked));
m_button5.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button5_clicked));
m_button6.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button6_clicked));
m_box.pack_start(m_area);
show_all_children();
}
MyWindow::~MyWindow() {
}
void MyWindow::on_button1_clicked() {
m_area.area_reset();
}
void MyWindow::on_button2_clicked() {
m_area.area_shrink();
}
void MyWindow::on_button3_clicked() {
m_area.area_left();
}
void MyWindow::on_button4_clicked() {
m_area.area_right();
}
void MyWindow::on_button5_clicked() {
m_area.area_up();
}
void MyWindow::on_button6_clicked() {
m_area.area_down();
}
/* MyArea.h */
#ifndef MYAREA_H_
#define MYAREA_H_
#include <gtkmm/drawingarea.h>
class MyArea : public Gtk::DrawingArea
{
public:
MyArea();
virtual ~MyArea();
void area_reset();
void area_shrink();
void area_left();
void area_right();
void area_up();
void area_down();
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 );
private:
double x_min;
double x_max;
double y_min;
double y_max;
double x_press;
double y_press;
double x_release;
double y_release;
};
#endif /* MYAREA_H_ */
/* MyArea.cpp */
#include "MyArea.h"
#include <complex>
#include <iostream>
using namespace std;
MyArea::MyArea() : x_min {-1.5}, x_max { 0.5}, y_min {-1.0}, y_max { 1.0},
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 );
}
MyArea::~MyArea() {
}
void MyArea::area_reset() {
x_min = -1.5;
x_max = 0.5;
y_min = -1.0;
y_max = 1.0;
get_window()->invalidate(true);
}
void MyArea::area_shrink() {
double xc = (x_min + x_max) / 2.0;
double yc = (y_min + y_max) / 2.0;
double xs = (x_max - xc) / 0.67;
double ys = (y_max - yc) / 0.67;
x_min = xc - xs;
x_max = xc + xs;
y_min = yc - ys;
y_max = yc + ys;
get_window()->invalidate(true);
}
void MyArea::area_left() {
double xc = (x_min + x_max) / 2.0;
double xs = (x_max - xc) * 0.67;
x_min += xs;
x_max += xs;
get_window()->invalidate(true);
}
void MyArea::area_right() {
double xc = (x_min + x_max) / 2.0;
double xs = (x_max - xc) * 0.67;
x_min -= xs;
x_max -= xs;
get_window()->invalidate(true);
}
void MyArea::area_up() {
double yc = (y_min + y_max) / 2.0;
double ys = (y_max - yc) * 0.67;
y_min += ys;
y_max += ys;
get_window()->invalidate(true);
}
void MyArea::area_down() {
double yc = (y_min + y_max) / 2.0;
double ys = (y_max - yc) * 0.67;
y_min -= ys;
y_max -= ys;
get_window()->invalidate(true);
}
bool MyArea::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 MyArea::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;
}
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";
cr->set_line_width(1.0);
double large = 100.0;
int kmax = 50;
for(int i=0;i<width;i++) {
for(int j=0;j<height;j++) {
double x=x_min+(x_max-x_min)*(double)i/(double)width;
double y=y_min+(y_max-y_min)*(double)j/(double)height;
complex<double> z=0.0;
complex<double> w=complex<double>(x,y);
int count=0;
for(int k=0;k<kmax;k++) {
z=z*z+w;
if(abs(z)>large) {
count = k;
break;
}
}
if(count) {
cr->set_source_rgba(0.9,(count%10)/10.0,0.3,1.0);
} else {
cr->set_source_rgba(0.0,0.2,0.7,1.0);
}
cr->rectangle((double)i, (double)j, 1.0, 1.0);
cr->stroke();
}
}
return true;
}