Загрузить исходник fox_test.cpp

#include "fox-1.6/fx.h"
#include <map>

char buf[16];

struct point {
    int x, y;
};

#define CANVAS_X 10
#define CANVAS_Y 10
#define CANVAS_WIDTH 180
#define CANVAS_HEIGHT 100
#define GRID_LEN 5 // размер зерна в холсте

class PaintWindow : public FXMainWindow {
FXDECLARE(PaintWindow)

    typedef std::map<std::pair<int, int>, point> PointMap;


private:
    FXCanvas *canvas; // холст, на котором будем рисовать
    FXLabel *count_label; // надпись
    FXFont *big_font; // шрифт для надписи
    int isMouseDown;
    FXColor drawColor; // цвет пикселей на холсте
    FXColor bgColor; // цвет фона холста
    PointMap pixels; // карта с координатами пикселей
    void setpixel(FXEvent *event);

protected:
    PaintWindow() { }

public:

    enum { // ID обработчиков событий
        ID_CANVAS = FXMainWindow::ID_LAST,
    };

    long onPaint(FXObject *, FXSelector, void *);

    long onMouseDown(FXObject *, FXSelector, void *);

    long onMouseUp(FXObject *, FXSelector, void *);

    long onMouseMove(FXObject *, FXSelector, void *);

    PaintWindow(FXApp *a);

    virtual void create();

    virtual ~PaintWindow();

};

FXDEFMAP(PaintWindow) PaintWindowMap[] = { // определяем обработчики событий
        FXMAPFUNC(SEL_PAINT, PaintWindow::ID_CANVAS, PaintWindow::onPaint),
        FXMAPFUNC(SEL_LEFTBUTTONPRESS, PaintWindow::ID_CANVAS, PaintWindow::onMouseDown),
        FXMAPFUNC(SEL_RIGHTBUTTONPRESS, PaintWindow::ID_CANVAS, PaintWindow::onMouseDown),
        FXMAPFUNC(SEL_LEFTBUTTONRELEASE, PaintWindow::ID_CANVAS, PaintWindow::onMouseUp),
        FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, PaintWindow::ID_CANVAS, PaintWindow::onMouseUp),
        FXMAPFUNC(SEL_MOTION, PaintWindow::ID_CANVAS, PaintWindow::onMouseMove)
};

FXIMPLEMENT(PaintWindow, FXMainWindow, PaintWindowMap, ARRAYNUMBER(PaintWindowMap))


PaintWindow::PaintWindow(FXApp *a) : FXMainWindow(a, a->getAppName(), NULL, NULL,
                                                  DECOR_TITLE | DECOR_BORDER | DECOR_MINIMIZE |
                                                  DECOR_CLOSE, //настраиваем вид окна
                                                  0, 0, 200, 300) { //выставляем размер окна

    canvas = new FXCanvas(this, this, ID_CANVAS, FRAME_SUNKEN | FRAME_THICK | LAYOUT_EXPLICIT,
                          CANVAS_X,
                          CANVAS_Y,
                          CANVAS_WIDTH,
                          CANVAS_HEIGHT); // задаём параметры холста, LAYOUT_EXPLICIT - абсолютное позиционирование

    count_label = new FXLabel(this, "...", NULL, LAYOUT_EXPLICIT, 34, 177, 133, 56);

    FXFontDesc fontdescription;
    getApp()->getNormalFont()->getFontDesc(fontdescription); // получаем стандартный шрифт

    big_font = new FXFont(getApp(), fontdescription.face, 37,
                          FXFont::Normal); // создаём стандартный шрифт с нужным размером
    big_font->create();

    count_label->setFont(big_font);

    drawColor = FXRGB(0, 0, 0);
    bgColor = FXRGB(255, 255, 255);

    isMouseDown = 0;
}


PaintWindow::~PaintWindow() {

}


void PaintWindow::create() {
    FXMainWindow::create();
    show(PLACEMENT_SCREEN); //показываем окно в центре экрана
}

void PaintWindow::setpixel(FXEvent *event) {
    int x = event->win_x;
    int y = event->win_y;

    if (x < 0 || y < 0 || x + 2 >= CANVAS_WIDTH  || y + 2 >= CANVAS_HEIGHT)
        return; // проверяем, не вышел ли курсор за пределы холста

    x = (event->win_x + 2) / GRID_LEN;
    y = (event->win_y + 2) / GRID_LEN;

    std::pair<int, int> p = std::make_pair(x * GRID_LEN, y * GRID_LEN); // создаём хеш из двух координат

    FXDCWindow dc(canvas);

    bool add = event->click_button == 1; // если кнопка левая, то рисуем, правой - удаляем

    dc.setForeground(add ? drawColor : bgColor);

    if (add) {
        point pixel;
        pixel.x = x * GRID_LEN;
        pixel.y = y * GRID_LEN;
        pixels[p] = pixel;
    } else {
        pixels.erase(p);
    }

    dc.fillRectangle(x * GRID_LEN, y * GRID_LEN, GRID_LEN, GRID_LEN); // рисуем квадратики

    sprintf(buf, "%d px", pixels.size());
    count_label->setText(buf); // обновляем надпись
}

long PaintWindow::onMouseUp(FXObject *, FXSelector, void *ptr) { // при отпускании мыши
    canvas->ungrab(); // отключаем перетаскивание в холсте
    if (isMouseDown) {
        FXDCWindow dc(canvas);
        dc.setForeground(drawColor);
        isMouseDown = 0;
    }
    return 1;
}

long PaintWindow::onMouseDown(FXObject *, FXSelector, void *ptr) { // при нажатии мыши
    canvas->grab(); // включаем перетаскивание в холсте
    setpixel((FXEvent *) ptr);
    isMouseDown = 1;
    return 1;
}


long PaintWindow::onMouseMove(FXObject *, FXSelector, void *ptr) {
    if (isMouseDown) {
        setpixel((FXEvent *) ptr);
    }
    return 1;
}


long PaintWindow::onPaint(FXObject *, FXSelector,
                          void *ptr) { //если окно сворачивается или выходит за пределы видимости, то его нужно перерисовать
    FXEvent *ev = (FXEvent *) ptr;
    FXDCWindow dc(canvas, ev);
    dc.setForeground(bgColor);
    dc.fillRectangle(ev->rect.x, ev->rect.y, ev->rect.w, ev->rect.h);

    typedef PointMap::iterator it_type;
    for (it_type iterator = pixels.begin();
         iterator != pixels.end(); iterator++) { // перебираем все пиксели наносим их на холст
        int x = iterator->second.x;
        int y = iterator->second.y;
        dc.setForeground(drawColor);
        dc.fillRectangle(x, y, GRID_LEN, GRID_LEN);

    }
    return 1;
}

int main(int argc, char **argv) {
    FXApp application("Pixels", "MultiMote");
    application.init(argc, argv);

    new PaintWindow(&application);
    application.create();

    return application.run();
}