<commit_before>/*
 * Copyright (c) 2013 Pavlo Lavrenenko
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <Rubik.h>
#include <ObjectManager.h>
#include <RenderManager.h>
#include <RenderState.h>
#include <Window.h>
#include <OpenGL.h>
#include <Shader.h>
#include <ObjectGroup.h>
#include <TextComponent.h>
#include <Layout.h>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdlib>

namespace Rubik {

Rubik::Rubik() {
    std::srand(static_cast<int>(std::time(nullptr)));
}

int Rubik::getShuffles() const {
    return this->shuffles;
}

void Rubik::setShuffles(int shuffles) {
    this->shuffles = shuffles;
}

void Rubik::onMouseMotion(int x, int y) {
    static Graphene::MousePosition mousePosition(this->getWindow()->getMousePosition());
    const Graphene::MouseState& mouseState = this->getWindow()->getMouseState();

    Math::Vec3 motionDirection(static_cast<float>(x - mousePosition.first), static_cast<float>(y - mousePosition.second), 0.0f);
    mousePosition = this->getWindow()->getMousePosition();

    int objectId = -1;
    bool isCubeSelected = false;
    bool isFrontCubeSelected = false;

    switch (this->state) {
        case GameState::RUNNING:
            if (mouseState[Graphene::MouseButton::BUTTON_LEFT] || mouseState[Graphene::MouseButton::BUTTON_RIGHT]) {
                int pickupX = x * this->pickupBuffer->getWidth() / this->getWindow()->getWidth();
                int pickupY = (this->getWindow()->getHeight() - y) * this->pickupBuffer->getHeight() / this->getWindow()->getHeight();
                this->pickupBuffer->getPixel(pickupX, pickupY, GL_RED_INTEGER, GL_INT, &objectId);

                isCubeSelected = (std::find(this->puzzleObjects.begin(), this->puzzleObjects.end(), objectId) != this->puzzleObjects.end());
                isFrontCubeSelected = (isCubeSelected && std::get<2>(this->puzzle->getCubePosition(objectId)) == 0);
            }

            if (mouseState[Graphene::MouseButton::BUTTON_LEFT] && !mouseState[Graphene::MouseButton::BUTTON_RIGHT]) {
                if (isFrontCubeSelected) {
                    this->rotateCube(objectId, motionDirection);
                }
            } else if (mouseState[Graphene::MouseButton::BUTTON_RIGHT] && !mouseState[Graphene::MouseButton::BUTTON_LEFT]) {
                if (isCubeSelected) {
                    this->rotateCube(-1, motionDirection);
                }
            }
            break;

        default:
            break;
    }
}

void Rubik::onKeyboardKey(Graphene::KeyboardKey key, bool state) {
    static bool pausePressed = false;
    static float rotationSpeed = 0.0f;

    switch (this->state) {
        case GameState::RUNNING:
            if (key == Graphene::KeyboardKey::KEY_S) {
                if (state) {
                    if (rotationSpeed == 0.0f) {
                        rotationSpeed = this->puzzle->getRotationSpeed();
                        this->puzzle->setRotationSpeed(rotationSpeed * 2.0f);
                    }
                } else {
                    this->puzzle->setRotationSpeed(rotationSpeed);
                    rotationSpeed = 0.0f;
                }
            }
            // Fall through

        case GameState::PAUSED:
            if (key == Graphene::KeyboardKey::KEY_P) {
                if (state) {
                    if (!pausePressed) {
                        this->state = (this->state == GameState::RUNNING) ? GameState::PAUSED : GameState::RUNNING;
                        pausePressed = true;
                    }
                } else {
                    pausePressed = false;
                }
            }
            break;

        default:
            break;
    }
}

void Rubik::onSetup() {
    Graphene::RenderStateCallback callback([](Graphene::RenderState* renderState, const std::shared_ptr<Graphene::Object>& object) {
        renderState->getShader()->setUniform("objectId", object->getId());
    });

    auto& renderState = Graphene::GetRenderManager().getRenderState(Graphene::RenderBuffer::ID);
    renderState->setShader(Graphene::GetObjectManager().createShader("shaders/object_pickup.shader"));
    renderState->setCallback(callback);

    this->setupScene();
    this->setupUI();
}

void Rubik::onIdle() {
    this->updateScene();
    this->updateUI();

    const Graphene::KeyboardState& keyboardState = this->getWindow()->getKeyboardState();
    if (this->state == GameState::RUNNING && !keyboardState[Graphene::KeyboardKey::KEY_S]) {
        this->gameTime += this->getFrameTime();
    }
}

void Rubik::setupScene() {
    /* Setup scene */

    auto& scene = this->createScene();
    scene->setAmbientEnergy(0.2f);

    auto& sceneRoot = scene->getRoot();
    auto& player = scene->getPlayer();
    this->puzzle = std::make_shared<Puzzle>();

    auto cube = std::make_shared<Graphene::ObjectGroup>();
    sceneRoot->addObject(cube);

    /* Populate scene with objects */

    auto& objectManager = Graphene::GetObjectManager();
    auto& renderManager = Graphene::GetRenderManager();
    renderManager.setLightPass(true);

    auto background = objectManager.createEntity("assets/background.entity");
    background->translate(0.0f, 0.0f, 5.0f);
    background->scale(25.0f, 25.0f, 1.0f);
    sceneRoot->addObject(background);

    auto camera = objectManager.createCamera(Graphene::ProjectionType::PERSPECTIVE);
    auto light = objectManager.createLight(Graphene::LightType::DIRECTED);

    player->addObject(camera);
    player->addObject(light);
    player->translate(0.25f, -0.25f, -4.5f);

    for (int i = -1; i <= 1; i++) {
        for (int j = -1; j <= 1; j++) {
            for (int k = -1; k <= 1; k++) {
                auto cubepart = std::make_shared<Graphene::ObjectGroup>();
                cube->addObject(cubepart);

                auto entity = objectManager.createEntity("assets/cubepart.entity");
                entity->translate(static_cast<float>(i), static_cast<float>(j), static_cast<float>(k));
                cubepart->addObject(entity);

                this->puzzle->addCube(entity);
                this->puzzleObjects.push_back(entity->getId());
            }
        }
    }

    cube->roll(-30.0f);
    cube->yaw(-30.0f);
    this->puzzle->shuffle(this->shuffles);

    /* Update default viewport with camera */

    auto& window = this->getWindow();
    auto& viewport = window->createViewport(0, 0, window->getWidth(), window->getHeight());
    viewport->setCamera(camera);

    /* Create framebuffer for object ID rendering and picking */

    this->pickupBuffer = this->createFrameBuffer(window->getWidth() / 2, window->getHeight() / 2, GL_R32I);
    auto& pickupViewport = pickupBuffer->createViewport(0, 0, this->pickupBuffer->getWidth(), this->pickupBuffer->getHeight());
    pickupViewport->setCamera(camera);
}

void Rubik::setupUI() {
    /* Setup scene */

    auto& uiScene = this->createScene();
    auto& uiRoot = uiScene->getRoot();

    /* Populate scene with objects */

    auto& objectManager = Graphene::GetObjectManager();
    auto camera = objectManager.createCamera(Graphene::ProjectionType::ORTHOGRAPHIC);
    camera->setNearPlane(-1.0f);  // NDC for 1:1 scale
    camera->setFarPlane(1.0f);  // NDC for 1:1 scale

    this->timeLabel = objectManager.createLabel(150, 20, "fonts/dejavu-sans.ttf", 12);
    this->movesLabel = objectManager.createLabel(150, 20, "fonts/dejavu-sans.ttf", 12);
    this->promptLabel = objectManager.createLabel(150, 20, "fonts/dejavu-sans.ttf", 12);

    uiRoot->addObject(camera);
    uiRoot->addObject(this->timeLabel);
    uiRoot->addObject(this->movesLabel);
    uiRoot->addObject(this->promptLabel);

    /* Arrange UI elements */

    auto& window = this->getWindow();

    auto uiLayout = std::make_shared<Graphene::Layout>();
    uiLayout->addComponent(this->timeLabel, (window->getWidth() - 120) / 2, window->getHeight() - 25);
    uiLayout->addComponent(this->movesLabel, (window->getWidth() - 70) / 2, window->getHeight() - 50);
    uiLayout->addComponent(this->promptLabel, (window->getWidth() - 110) / 2, 10);

    /* Update viewport with camera */

    auto& overlay = window->createOverlay(0, 0, window->getWidth(), window->getHeight());
    overlay->setCamera(camera);
    overlay->setLayout(uiLayout);
}

void Rubik::updateScene() {
    const Graphene::KeyboardState& keyboardState = this->getWindow()->getKeyboardState();

    switch (this->state) {
        case GameState::RUNNING:
            if (this->puzzle->isSolved()) {
                this->state = GameState::FINISHED;
            } else if (keyboardState[Graphene::KeyboardKey::KEY_ESCAPE]) {
                this->state = GameState::QUIT;
            } else if (keyboardState[Graphene::KeyboardKey::KEY_S]) {
                this->puzzle->selectCube(this->puzzleObjects[std::rand() % this->puzzleObjects.size()]);
                this->puzzle->setAnimationState(static_cast<AnimationState>(std::rand() % 4 + 1));
            }

            this->puzzle->update(this->getFrameTime());
            break;

        case GameState::QUIT:
            if (keyboardState[Graphene::KeyboardKey::KEY_Y]) {
                this->exit(0);
            } else if (keyboardState[Graphene::KeyboardKey::KEY_N]) {
                this->state = GameState::RUNNING;
            }
            break;

        case GameState::FINISHED:
            if (keyboardState[Graphene::KeyboardKey::KEY_N]) {
                this->exit(0);
            } else if (keyboardState[Graphene::KeyboardKey::KEY_Y]) {
                this->moves = 0;
                this->gameTime = 0.0f;
                this->state = GameState::RUNNING;
                this->puzzle->shuffle(this->shuffles);
            }
            break;

        default:
            break;
    }
}

void Rubik::updateUI() {
    int gameTime = static_cast<int>(this->gameTime);
    int seconds = gameTime % 60;
    int minutes = gameTime / 60;
    int hours = gameTime / 3600;

    std::wstringstream time;
    time << "Time: " << std::setw(2) << std::setfill(L'0') << hours << ":"
                     << std::setw(2) << std::setfill(L'0') << minutes << ":"
                     << std::setw(2) << std::setfill(L'0') << seconds;
    this->timeLabel->getComponent<Graphene::TextComponent>()->setText(time.str());

    std::wstringstream moves;
    moves << "Moves: " << this->moves;
    this->movesLabel->getComponent<Graphene::TextComponent>()->setText(moves.str());

    switch (this->state) {
        case GameState::FINISHED:
            this->promptLabel->getComponent<Graphene::TextComponent>()->setText(L"New game? Y/N");
            this->promptLabel->setVisible(true);
            break;

        case GameState::PAUSED:
            this->promptLabel->getComponent<Graphene::TextComponent>()->setText(L"       Paused");
            this->promptLabel->setVisible(true);
            break;

        case GameState::QUIT:
            this->promptLabel->getComponent<Graphene::TextComponent>()->setText(L"    Quit? Y/N");
            this->promptLabel->setVisible(true);
            break;

        default:
            this->promptLabel->setVisible(false);
            break;
    }
}

void Rubik::rotateCube(int objectId, const Math::Vec3& direction) {
    if (this->state == GameState::PAUSED) {
        return;  // No action on pause
    }

    if (direction.length() < 1.5f) {
        return;  // Movement is too short
    }

    if (objectId != -1 && this->puzzle->getAnimationState() == AnimationState::IDLE) {
        this->moves++;
    }

    float xDirection = direction.get(Math::Vec3::X);
    float yDirection = direction.get(Math::Vec3::Y);
    AnimationState puzzleState = AnimationState::IDLE;

    if (fabsf(xDirection) > fabsf(yDirection)) {
        puzzleState = (xDirection > 0) ? AnimationState::RIGHT_ROTATION : AnimationState::LEFT_ROTATION;
    } else {
        puzzleState = (yDirection > 0) ? AnimationState::DOWN_ROTATION : AnimationState::UP_ROTATION;
    }

    this->puzzle->selectCube(objectId);
    this->puzzle->setAnimationState(puzzleState);
}

}  // namespace Rubik
<commit_msg>Adapt code to Graphene::Layout class changes<commit_after>/*
 * Copyright (c) 2013 Pavlo Lavrenenko
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <Rubik.h>
#include <ObjectManager.h>
#include <RenderManager.h>
#include <RenderState.h>
#include <Window.h>
#include <OpenGL.h>
#include <Shader.h>
#include <ObjectGroup.h>
#include <TextComponent.h>
#include <Layout.h>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdlib>

namespace Rubik {

Rubik::Rubik() {
    std::srand(static_cast<int>(std::time(nullptr)));
}

int Rubik::getShuffles() const {
    return this->shuffles;
}

void Rubik::setShuffles(int shuffles) {
    this->shuffles = shuffles;
}

void Rubik::onMouseMotion(int x, int y) {
    static Graphene::MousePosition mousePosition(this->getWindow()->getMousePosition());
    const Graphene::MouseState& mouseState = this->getWindow()->getMouseState();

    Math::Vec3 motionDirection(static_cast<float>(x - mousePosition.first), static_cast<float>(y - mousePosition.second), 0.0f);
    mousePosition = this->getWindow()->getMousePosition();

    int objectId = -1;
    bool isCubeSelected = false;
    bool isFrontCubeSelected = false;

    switch (this->state) {
        case GameState::RUNNING:
            if (mouseState[Graphene::MouseButton::BUTTON_LEFT] || mouseState[Graphene::MouseButton::BUTTON_RIGHT]) {
                int pickupX = x * this->pickupBuffer->getWidth() / this->getWindow()->getWidth();
                int pickupY = (this->getWindow()->getHeight() - y) * this->pickupBuffer->getHeight() / this->getWindow()->getHeight();
                this->pickupBuffer->getPixel(pickupX, pickupY, GL_RED_INTEGER, GL_INT, &objectId);

                isCubeSelected = (std::find(this->puzzleObjects.begin(), this->puzzleObjects.end(), objectId) != this->puzzleObjects.end());
                isFrontCubeSelected = (isCubeSelected && std::get<2>(this->puzzle->getCubePosition(objectId)) == 0);
            }

            if (mouseState[Graphene::MouseButton::BUTTON_LEFT] && !mouseState[Graphene::MouseButton::BUTTON_RIGHT]) {
                if (isFrontCubeSelected) {
                    this->rotateCube(objectId, motionDirection);
                }
            } else if (mouseState[Graphene::MouseButton::BUTTON_RIGHT] && !mouseState[Graphene::MouseButton::BUTTON_LEFT]) {
                if (isCubeSelected) {
                    this->rotateCube(-1, motionDirection);
                }
            }
            break;

        default:
            break;
    }
}

void Rubik::onKeyboardKey(Graphene::KeyboardKey key, bool state) {
    static bool pausePressed = false;
    static float rotationSpeed = 0.0f;

    switch (this->state) {
        case GameState::RUNNING:
            if (key == Graphene::KeyboardKey::KEY_S) {
                if (state) {
                    if (rotationSpeed == 0.0f) {
                        rotationSpeed = this->puzzle->getRotationSpeed();
                        this->puzzle->setRotationSpeed(rotationSpeed * 2.0f);
                    }
                } else {
                    this->puzzle->setRotationSpeed(rotationSpeed);
                    rotationSpeed = 0.0f;
                }
            }
            // Fall through

        case GameState::PAUSED:
            if (key == Graphene::KeyboardKey::KEY_P) {
                if (state) {
                    if (!pausePressed) {
                        this->state = (this->state == GameState::RUNNING) ? GameState::PAUSED : GameState::RUNNING;
                        pausePressed = true;
                    }
                } else {
                    pausePressed = false;
                }
            }
            break;

        default:
            break;
    }
}

void Rubik::onSetup() {
    Graphene::RenderStateCallback callback([](Graphene::RenderState* renderState, const std::shared_ptr<Graphene::Object>& object) {
        renderState->getShader()->setUniform("objectId", object->getId());
    });

    auto& renderState = Graphene::GetRenderManager().getRenderState(Graphene::RenderBuffer::ID);
    renderState->setShader(Graphene::GetObjectManager().createShader("shaders/object_pickup.shader"));
    renderState->setCallback(callback);

    this->setupScene();
    this->setupUI();
}

void Rubik::onIdle() {
    this->updateScene();
    this->updateUI();

    const Graphene::KeyboardState& keyboardState = this->getWindow()->getKeyboardState();
    if (this->state == GameState::RUNNING && !keyboardState[Graphene::KeyboardKey::KEY_S]) {
        this->gameTime += this->getFrameTime();
    }
}

void Rubik::setupScene() {
    /* Setup scene */

    auto& scene = this->createScene();
    scene->setAmbientEnergy(0.2f);

    auto& sceneRoot = scene->getRoot();
    auto& player = scene->getPlayer();
    this->puzzle = std::make_shared<Puzzle>();

    auto cube = std::make_shared<Graphene::ObjectGroup>();
    sceneRoot->addObject(cube);

    /* Populate scene with objects */

    auto& objectManager = Graphene::GetObjectManager();
    auto& renderManager = Graphene::GetRenderManager();
    renderManager.setLightPass(true);

    auto background = objectManager.createEntity("assets/background.entity");
    background->translate(0.0f, 0.0f, 5.0f);
    background->scale(25.0f, 25.0f, 1.0f);
    sceneRoot->addObject(background);

    auto camera = objectManager.createCamera(Graphene::ProjectionType::PERSPECTIVE);
    auto light = objectManager.createLight(Graphene::LightType::DIRECTED);

    player->addObject(camera);
    player->addObject(light);
    player->translate(0.25f, -0.25f, -4.5f);

    for (int i = -1; i <= 1; i++) {
        for (int j = -1; j <= 1; j++) {
            for (int k = -1; k <= 1; k++) {
                auto cubepart = std::make_shared<Graphene::ObjectGroup>();
                cube->addObject(cubepart);

                auto entity = objectManager.createEntity("assets/cubepart.entity");
                entity->translate(static_cast<float>(i), static_cast<float>(j), static_cast<float>(k));
                cubepart->addObject(entity);

                this->puzzle->addCube(entity);
                this->puzzleObjects.push_back(entity->getId());
            }
        }
    }

    cube->roll(-30.0f);
    cube->yaw(-30.0f);
    this->puzzle->shuffle(this->shuffles);

    /* Update default viewport with camera */

    auto& window = this->getWindow();
    auto& viewport = window->createViewport(0, 0, window->getWidth(), window->getHeight());
    viewport->setCamera(camera);

    /* Create framebuffer for object ID rendering and picking */

    this->pickupBuffer = this->createFrameBuffer(window->getWidth() / 2, window->getHeight() / 2, GL_R32I);
    auto& pickupViewport = pickupBuffer->createViewport(0, 0, this->pickupBuffer->getWidth(), this->pickupBuffer->getHeight());
    pickupViewport->setCamera(camera);
}

void Rubik::setupUI() {
    /* Setup scene */

    auto& uiScene = this->createScene();
    auto& uiRoot = uiScene->getRoot();

    /* Populate scene with objects */

    auto& objectManager = Graphene::GetObjectManager();
    auto camera = objectManager.createCamera(Graphene::ProjectionType::ORTHOGRAPHIC);
    camera->setNearPlane(-1.0f);  // NDC for 1:1 scale
    camera->setFarPlane(1.0f);  // NDC for 1:1 scale

    this->timeLabel = objectManager.createLabel(150, 20, "fonts/dejavu-sans.ttf", 12);
    this->movesLabel = objectManager.createLabel(150, 20, "fonts/dejavu-sans.ttf", 12);
    this->promptLabel = objectManager.createLabel(150, 20, "fonts/dejavu-sans.ttf", 12);

    uiRoot->addObject(camera);
    uiRoot->addObject(this->timeLabel);
    uiRoot->addObject(this->movesLabel);
    uiRoot->addObject(this->promptLabel);

    /* Arrange UI elements */

    auto& window = this->getWindow();

    auto uiLayout = std::make_shared<Graphene::Layout>();
    uiLayout->addEntity(this->timeLabel, (window->getWidth() - 120) / 2, window->getHeight() - 25);
    uiLayout->addEntity(this->movesLabel, (window->getWidth() - 70) / 2, window->getHeight() - 50);
    uiLayout->addEntity(this->promptLabel, (window->getWidth() - 110) / 2, 10);

    /* Update viewport with camera */

    auto& overlay = window->createOverlay(0, 0, window->getWidth(), window->getHeight());
    overlay->setCamera(camera);
    overlay->setLayout(uiLayout);
}

void Rubik::updateScene() {
    const Graphene::KeyboardState& keyboardState = this->getWindow()->getKeyboardState();

    switch (this->state) {
        case GameState::RUNNING:
            if (this->puzzle->isSolved()) {
                this->state = GameState::FINISHED;
            } else if (keyboardState[Graphene::KeyboardKey::KEY_ESCAPE]) {
                this->state = GameState::QUIT;
            } else if (keyboardState[Graphene::KeyboardKey::KEY_S]) {
                this->puzzle->selectCube(this->puzzleObjects[std::rand() % this->puzzleObjects.size()]);
                this->puzzle->setAnimationState(static_cast<AnimationState>(std::rand() % 4 + 1));
            }

            this->puzzle->update(this->getFrameTime());
            break;

        case GameState::QUIT:
            if (keyboardState[Graphene::KeyboardKey::KEY_Y]) {
                this->exit(0);
            } else if (keyboardState[Graphene::KeyboardKey::KEY_N]) {
                this->state = GameState::RUNNING;
            }
            break;

        case GameState::FINISHED:
            if (keyboardState[Graphene::KeyboardKey::KEY_N]) {
                this->exit(0);
            } else if (keyboardState[Graphene::KeyboardKey::KEY_Y]) {
                this->moves = 0;
                this->gameTime = 0.0f;
                this->state = GameState::RUNNING;
                this->puzzle->shuffle(this->shuffles);
            }
            break;

        default:
            break;
    }
}

void Rubik::updateUI() {
    int gameTime = static_cast<int>(this->gameTime);
    int seconds = gameTime % 60;
    int minutes = gameTime / 60;
    int hours = gameTime / 3600;

    std::wstringstream time;
    time << "Time: " << std::setw(2) << std::setfill(L'0') << hours << ":"
                     << std::setw(2) << std::setfill(L'0') << minutes << ":"
                     << std::setw(2) << std::setfill(L'0') << seconds;
    this->timeLabel->getComponent<Graphene::TextComponent>()->setText(time.str());

    std::wstringstream moves;
    moves << "Moves: " << this->moves;
    this->movesLabel->getComponent<Graphene::TextComponent>()->setText(moves.str());

    switch (this->state) {
        case GameState::FINISHED:
            this->promptLabel->getComponent<Graphene::TextComponent>()->setText(L"New game? Y/N");
            this->promptLabel->setVisible(true);
            break;

        case GameState::PAUSED:
            this->promptLabel->getComponent<Graphene::TextComponent>()->setText(L"       Paused");
            this->promptLabel->setVisible(true);
            break;

        case GameState::QUIT:
            this->promptLabel->getComponent<Graphene::TextComponent>()->setText(L"    Quit? Y/N");
            this->promptLabel->setVisible(true);
            break;

        default:
            this->promptLabel->setVisible(false);
            break;
    }
}

void Rubik::rotateCube(int objectId, const Math::Vec3& direction) {
    if (this->state == GameState::PAUSED) {
        return;  // No action on pause
    }

    if (direction.length() < 1.5f) {
        return;  // Movement is too short
    }

    if (objectId != -1 && this->puzzle->getAnimationState() == AnimationState::IDLE) {
        this->moves++;
    }

    float xDirection = direction.get(Math::Vec3::X);
    float yDirection = direction.get(Math::Vec3::Y);
    AnimationState puzzleState = AnimationState::IDLE;

    if (fabsf(xDirection) > fabsf(yDirection)) {
        puzzleState = (xDirection > 0) ? AnimationState::RIGHT_ROTATION : AnimationState::LEFT_ROTATION;
    } else {
        puzzleState = (yDirection > 0) ? AnimationState::DOWN_ROTATION : AnimationState::UP_ROTATION;
    }

    this->puzzle->selectCube(objectId);
    this->puzzle->setAnimationState(puzzleState);
}

}  // namespace Rubik
<|endoftext|>


<commit_before>/* TMP36 library

 Copyright 2017 Isaac100

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 This library converts the analog values from a TMP36 temperature
 sensor directly into Celcius and Fahrenheit so you don't have to.
 */

#include "Arduino.h"
#include "TMP36.h"

TMP36::TMP36(uint8_t pin)
{
  pinMode(pin, INPUT);
  _pin = pin;
}

void TMP36::getValues() {
  _value = analogRead(_pin);
  _voltage = (_value/1024.0) * 5.0;
  _tempC = (_voltage - .5) * 100;
  _tempF = (_tempC * 1.8) + 32;
}

float TMP36::getVoltage() {
 getValues();
 return _voltage;
}

float TMP36::getTempC() {
  getValues();
  return _tempC;
}

float TMP36::getTempF() {
  getValues();
  return _tempF;
}

<commit_msg>Update TMP36.cpp<commit_after>/* TMP36 library

 Copyright 2017 Isaac100

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 This library converts the analog values from a TMP36 temperature
 sensor directly into Celcius and Fahrenheit so you don't have to.
 */

#include "Arduino.h"
#include "TMP36.h"

TMP36::TMP36(uint8_t pin)
{
  pinMode(pin, INPUT);
  _pin = pin;
}

void TMP36::getValues() {
 _value = analogRead(_pin);
 _voltage = (_value/1024.0) * 5.0;
 _tempC = (_voltage - .5) * 100;
 _tempF = (_tempC * 1.8) + 32;
}

float TMP36::getVoltage() {
 getValues();
 return _voltage;
}

float TMP36::getTempC() {
 getValues();
 return _tempC;
}

float TMP36::getTempF() {
 getValues();
 return _tempF;
}

<|endoftext|>


<commit_before>/*****************************************************************************************[Main.cc]
Copyright (c) 2007, Niklas Sorensson

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>

#include "utils/Options.h"
#include "utils/System.h"
#include "simp/SimpSolver.h"
#include "circ/Circ.h"
#include "circ/Clausify.h"
#include "circ/Aiger.h"
#include "circ/DagShrink.h"
#include "circ/SatSweep.h"

using namespace Minisat;

//=================================================================================================

static
void printStats(Solver& solver)
{
    double cpu_time = cpuTime();
    double mem_used = memUsed();
    printf("restarts              : %"PRIu64"\n", solver.starts);
    printf("conflicts             : %-12"PRIu64"   (%.0f /sec)\n", solver.conflicts   , solver.conflicts   /cpu_time);
    printf("decisions             : %-12"PRIu64"   (%4.2f %% random) (%.0f /sec)\n", solver.decisions, (float)solver.rnd_decisions*100 / (float)solver.decisions, solver.decisions   /cpu_time);
    printf("propagations          : %-12"PRIu64"   (%.0f /sec)\n", solver.propagations, solver.propagations/cpu_time);
    printf("conflict literals     : %-12"PRIu64"   (%4.2f %% deleted)\n", solver.tot_literals, (solver.max_literals - solver.tot_literals)*100 / (double)solver.max_literals);
    if (mem_used != 0) printf("Memory used           : %.2f MB\n", mem_used);
    printf("CPU time              : %g s\n", cpu_time);
}

SimpSolver* solver;
static void SIGINT_handler(int signum) {
    printf("\n"); printf("*** INTERRUPTED ***\n");
    printStats(*solver);
    printf("\n"); printf("*** INTERRUPTED ***\n");
    exit(1); }

//=================================================================================================
// Main:

int main(int argc, char** argv)
{
    setUsageHelp("USAGE: %s [options] <input-file> <result-output-file>\n\n  where input is in plain or gzipped binary AIGER.\n");
    printf("Using MiniSat 2.0 beta\n");

#if defined(__linux__)
    fpu_control_t oldcw, newcw;
    _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
    printf("WARNING: for repeatability, setting FPU to use double precision\n");
#endif

    // Extra options:
    //
    BoolOption   pre            ("MAIN", "pre",    "Completely turn on/off any preprocessing.", true);
    BoolOption   clausify_naive ("MAIN", "clausify-naive", "Use naive clausification", false);
    StringOption aiger          ("MAIN", "aiger",  "If given, stop after preprocessing AIG and write the result to this file.");
    StringOption dimacs         ("MAIN", "dimacs", "If given, stop after producing CNF and write the result to this file.");
    IntOption    dash_iters     ("MAIN", "dash-iters", "Number of DAG Aware Rewriting iterations.", 5);
    BoolOption   split_output   ("MAIN", "split-output", "Split the topmost output conjunctions into multiple outputs.", true);
    BoolOption   sweep          ("MAIN", "sweep", "Perform SAT-sweeping of the AIG.", false);

    parseOptions(argc, argv, true);

    SimpSolver S;
    double     initial_time = cpuTime();

    if (!pre) S.eliminate(true);

    solver = &S;
    signal(SIGINT,SIGINT_handler);
    signal(SIGHUP,SIGINT_handler);

    vec<Var> input_vars;

    if (argc < 2 || argc > 3)
        printUsageAndExit(argc, argv);
    else {
        printf("============================[ Problem Statistics ]=============================\n");
        printf("|                                                                             |\n");

        Circ  c;
        Box   b;
        Flops flp;
        readAiger(argv[1], c, b, flp);

        if (flp.size() > 0)
            fprintf(stderr, "ERROR! Sequential circuits not supported!\n"), exit(1);

        //if (c.outputs.size() != 1)
        //    fprintf(stderr, "ERROR! Exactly 1 output expected, found %d!\n", c.outputs.size()), exit(1);
        if (split_output)
            splitOutputs(c, b, flp);

        printf("|  Number of inputs:     %12d                                         |\n", c.nInps());
        printf("|  Number of outputs:    %12d                                         |\n", b.outs.size());
        printf("|  Number of gates:      %12d                                         |\n", c.nGates());

        double parsed_time = cpuTime();
        printf("|  Parse time:           %12.2f s                                       |\n", parsed_time - initial_time);

        if (sweep){
            // Create a list of all references into the circuit that we need to keep:
            vec<Sig> sinks;
            extractSigs(b,   sinks);
            extractSigs(flp, sinks); // Should be empty.

            // Set up the DAG-shrink environment:
            SatSweeper<Solver> sweeper(c, sinks);
            sweeper.sweep();

            // Map the old reference to point into the shrunk circuit:
            map(sweeper.resultMap(), b);
            map(sweeper.resultMap(), flp); // Should be empty.

            // Copy the shrunk circuit back:
            sweeper.copyResult(c);

            printf("|  Number of inputs:     %12d                                         |\n", c.nInps());
            printf("|  Number of outputs:    %12d                                         |\n", b.outs.size());
            printf("|  Number of gates:      %12d                                         |\n", c.nGates());
        }

        if (dash_iters > 0){
            // Create a list of all references into the circuit that we need to keep:
            vec<Sig> sinks;
            extractSigs(b,   sinks);
            extractSigs(flp, sinks); // Should be empty.

            // Set up the DAG-shrink environment:
            DagShrinker dag(c, sinks);
            dag.shrinkIter(dash_iters);

            // Map the old reference to point into the shrunk circuit:
            map(dag.resultMap(), b);
            map(dag.resultMap(), flp); // Should be empty.

            // Copy the shrunk circuit back:
            dag.copyResult(c);
        }

        // void circInfo (      Circ& c, Gate g, GSet& reachable, int& n_ands, int& n_xors, int& n_muxes, int& tot_ands);
        // {
        //     GSet r; int n_ands = 0, n_xors = 0, n_muxs = 0, tot_ands = 0;
        //
        //     for (int i = 0; i < c.outputs.size(); i++)
        //         circInfo(c.circ, gate(c.outputs[i]), r, n_ands, n_xors, n_muxs, tot_ands);
        //     fprintf(stderr, " >> ANDS = %d, XORS = %d, MUXES = %d, TOT = %d\n", n_ands, n_xors, n_muxs, tot_ands);
        // }

        if (aiger != NULL){
            printf("==============================[ Writing AIGER ]================================\n");
            writeAiger(aiger, c, b, flp);
            exit(0);
        }

        vec<Lit> unit;
        if (clausify_naive){
            NaiveClausifyer<SimpSolver> cl(c, S);
            for (int i = 0; i < b.outs.size(); i++){
                unit.clear();
                unit.push(cl.clausify(b.outs[i]));
                assert(S.okay());
                assert(S.value(unit.last()) == l_Undef);
                S.addClause(unit);
            }

            for (int i = 0; i < b.inps.size(); i++)
                input_vars.push(cl.clausify(b.inps[i]));

        }else {
            Clausifyer<SimpSolver> cl(c, S);
            //cl.prepare();

            for (int i = 0; i < b.outs.size(); i++)
                cl.assume(b.outs[i]);

            for (int i = 0; i < b.inps.size(); i++){
                Lit x = cl.clausify(b.inps[i]);
                assert(!sign(x));
                input_vars.push(var(x));
            }
        }

        printf("===========================[ Clausify Statistics ]=============================\n");
        printf("|                                                                             |\n");
        printf("|  Number of variables:  %12d                                         |\n", S.nVars());
        printf("|  Number of clauses:    %12d                                         |\n", S.nClauses());

        double clausify_time = cpuTime();
        printf("|  Clausify time:        %12.2f s                                       |\n", clausify_time - parsed_time);
    }

    // Freeze input vars:
    //for (int i = 0; i < input_vars.size(); i++)
    //    S.setFrozen(input_vars[i], true);

    if (pre){
        double simplified_time_before = cpuTime();
        S.eliminate(true);
        printf("|  Simplification time:  %12.2f s                                       |\n", cpuTime() - simplified_time_before);
    }
    printf("|                                                                             |\n");

    FILE* res = (argc >= 3) ? fopen(argv[2], "wb") : NULL;

    if (!S.okay()){
        if (res != NULL) fprintf(res, "0\n"), fclose(res);
        printf("===============================================================================\n");
        printf("Solved by simplification\n");
        printStats(S);
        printf("\n");
        printf("UNSATISFIABLE\n");
        exit(20);
    }

    if (dimacs){
        printf("==============================[ Writing DIMACS ]===============================\n");
        S.toDimacs(dimacs);
        printStats(S);
        exit(0);
    }else{
        bool ret = S.solve();
        printStats(S);
        printf("\n");
        printf(ret ? "SATISFIABLE\n" : "UNSATISFIABLE\n");
        if (res != NULL){
            if (ret){
                fprintf(res, "1\n");
                for (int i = 0; i < input_vars.size(); i++){
                    Var inp = input_vars[i];
                    if (S.model[inp] == l_Undef)
                        fprintf(res, "x");
                    else if (S.model[inp] == l_True)
                        fprintf(res, "1");
                    else
                        fprintf(res, "0");
                }
                fprintf(res, "\n");
            }else
                fprintf(res, "0\n");
            fclose(res);
        }
#ifdef NDEBUG
        exit(ret ? 10 : 20);     // (faster than "return", which will invoke the destructor for 'Solver')
#endif
    }
}
<commit_msg>Bugfix: use signal-safe version of 'exit()' in signal-handler.<commit_after>/*****************************************************************************************[Main.cc]
Copyright (c) 2007, Niklas Sorensson

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>

#include "utils/Options.h"
#include "utils/System.h"
#include "simp/SimpSolver.h"
#include "circ/Circ.h"
#include "circ/Clausify.h"
#include "circ/Aiger.h"
#include "circ/DagShrink.h"
#include "circ/SatSweep.h"

using namespace Minisat;

//=================================================================================================

static
void printStats(Solver& solver)
{
    double cpu_time = cpuTime();
    double mem_used = memUsed();
    printf("restarts              : %"PRIu64"\n", solver.starts);
    printf("conflicts             : %-12"PRIu64"   (%.0f /sec)\n", solver.conflicts   , solver.conflicts   /cpu_time);
    printf("decisions             : %-12"PRIu64"   (%4.2f %% random) (%.0f /sec)\n", solver.decisions, (float)solver.rnd_decisions*100 / (float)solver.decisions, solver.decisions   /cpu_time);
    printf("propagations          : %-12"PRIu64"   (%.0f /sec)\n", solver.propagations, solver.propagations/cpu_time);
    printf("conflict literals     : %-12"PRIu64"   (%4.2f %% deleted)\n", solver.tot_literals, (solver.max_literals - solver.tot_literals)*100 / (double)solver.max_literals);
    if (mem_used != 0) printf("Memory used           : %.2f MB\n", mem_used);
    printf("CPU time              : %g s\n", cpu_time);
}

SimpSolver* solver;
static void SIGINT_handler(int signum) {
    printf("\n"); printf("*** INTERRUPTED ***\n");
    printStats(*solver);
    printf("\n"); printf("*** INTERRUPTED ***\n");
    _exit(1); }

//=================================================================================================
// Main:

int main(int argc, char** argv)
{
    setUsageHelp("USAGE: %s [options] <input-file> <result-output-file>\n\n  where input is in plain or gzipped binary AIGER.\n");
    printf("Using MiniSat 2.0 beta\n");

#if defined(__linux__)
    fpu_control_t oldcw, newcw;
    _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
    printf("WARNING: for repeatability, setting FPU to use double precision\n");
#endif

    // Extra options:
    //
    BoolOption   pre            ("MAIN", "pre",    "Completely turn on/off any preprocessing.", true);
    BoolOption   clausify_naive ("MAIN", "clausify-naive", "Use naive clausification", false);
    StringOption aiger          ("MAIN", "aiger",  "If given, stop after preprocessing AIG and write the result to this file.");
    StringOption dimacs         ("MAIN", "dimacs", "If given, stop after producing CNF and write the result to this file.");
    IntOption    dash_iters     ("MAIN", "dash-iters", "Number of DAG Aware Rewriting iterations.", 5);
    BoolOption   split_output   ("MAIN", "split-output", "Split the topmost output conjunctions into multiple outputs.", true);
    BoolOption   sweep          ("MAIN", "sweep", "Perform SAT-sweeping of the AIG.", false);

    parseOptions(argc, argv, true);

    SimpSolver S;
    double     initial_time = cpuTime();

    if (!pre) S.eliminate(true);

    solver = &S;
    signal(SIGINT,SIGINT_handler);
    signal(SIGHUP,SIGINT_handler);

    vec<Var> input_vars;

    if (argc < 2 || argc > 3)
        printUsageAndExit(argc, argv);
    else {
        printf("============================[ Problem Statistics ]=============================\n");
        printf("|                                                                             |\n");

        Circ  c;
        Box   b;
        Flops flp;
        readAiger(argv[1], c, b, flp);

        if (flp.size() > 0)
            fprintf(stderr, "ERROR! Sequential circuits not supported!\n"), exit(1);

        //if (c.outputs.size() != 1)
        //    fprintf(stderr, "ERROR! Exactly 1 output expected, found %d!\n", c.outputs.size()), exit(1);
        if (split_output)
            splitOutputs(c, b, flp);

        printf("|  Number of inputs:     %12d                                         |\n", c.nInps());
        printf("|  Number of outputs:    %12d                                         |\n", b.outs.size());
        printf("|  Number of gates:      %12d                                         |\n", c.nGates());

        double parsed_time = cpuTime();
        printf("|  Parse time:           %12.2f s                                       |\n", parsed_time - initial_time);

        if (sweep){
            // Create a list of all references into the circuit that we need to keep:
            vec<Sig> sinks;
            extractSigs(b,   sinks);
            extractSigs(flp, sinks); // Should be empty.

            // Set up the DAG-shrink environment:
            SatSweeper<Solver> sweeper(c, sinks);
            sweeper.sweep();

            // Map the old reference to point into the shrunk circuit:
            map(sweeper.resultMap(), b);
            map(sweeper.resultMap(), flp); // Should be empty.

            // Copy the shrunk circuit back:
            sweeper.copyResult(c);

            printf("|  Number of inputs:     %12d                                         |\n", c.nInps());
            printf("|  Number of outputs:    %12d                                         |\n", b.outs.size());
            printf("|  Number of gates:      %12d                                         |\n", c.nGates());
        }

        if (dash_iters > 0){
            // Create a list of all references into the circuit that we need to keep:
            vec<Sig> sinks;
            extractSigs(b,   sinks);
            extractSigs(flp, sinks); // Should be empty.

            // Set up the DAG-shrink environment:
            DagShrinker dag(c, sinks);
            dag.shrinkIter(dash_iters);

            // Map the old reference to point into the shrunk circuit:
            map(dag.resultMap(), b);
            map(dag.resultMap(), flp); // Should be empty.

            // Copy the shrunk circuit back:
            dag.copyResult(c);
        }

        // void circInfo (      Circ& c, Gate g, GSet& reachable, int& n_ands, int& n_xors, int& n_muxes, int& tot_ands);
        // {
        //     GSet r; int n_ands = 0, n_xors = 0, n_muxs = 0, tot_ands = 0;
        //
        //     for (int i = 0; i < c.outputs.size(); i++)
        //         circInfo(c.circ, gate(c.outputs[i]), r, n_ands, n_xors, n_muxs, tot_ands);
        //     fprintf(stderr, " >> ANDS = %d, XORS = %d, MUXES = %d, TOT = %d\n", n_ands, n_xors, n_muxs, tot_ands);
        // }

        if (aiger != NULL){
            printf("==============================[ Writing AIGER ]================================\n");
            writeAiger(aiger, c, b, flp);
            exit(0);
        }

        vec<Lit> unit;
        if (clausify_naive){
            NaiveClausifyer<SimpSolver> cl(c, S);
            for (int i = 0; i < b.outs.size(); i++){
                unit.clear();
                unit.push(cl.clausify(b.outs[i]));
                assert(S.okay());
                assert(S.value(unit.last()) == l_Undef);
                S.addClause(unit);
            }

            for (int i = 0; i < b.inps.size(); i++)
                input_vars.push(cl.clausify(b.inps[i]));

        }else {
            Clausifyer<SimpSolver> cl(c, S);
            //cl.prepare();

            for (int i = 0; i < b.outs.size(); i++)
                cl.assume(b.outs[i]);

            for (int i = 0; i < b.inps.size(); i++){
                Lit x = cl.clausify(b.inps[i]);
                assert(!sign(x));
                input_vars.push(var(x));
            }
        }

        printf("===========================[ Clausify Statistics ]=============================\n");
        printf("|                                                                             |\n");
        printf("|  Number of variables:  %12d                                         |\n", S.nVars());
        printf("|  Number of clauses:    %12d                                         |\n", S.nClauses());

        double clausify_time = cpuTime();
        printf("|  Clausify time:        %12.2f s                                       |\n", clausify_time - parsed_time);
    }

    // Freeze input vars:
    //for (int i = 0; i < input_vars.size(); i++)
    //    S.setFrozen(input_vars[i], true);

    if (pre){
        double simplified_time_before = cpuTime();
        S.eliminate(true);
        printf("|  Simplification time:  %12.2f s                                       |\n", cpuTime() - simplified_time_before);
    }
    printf("|                                                                             |\n");

    FILE* res = (argc >= 3) ? fopen(argv[2], "wb") : NULL;

    if (!S.okay()){
        if (res != NULL) fprintf(res, "0\n"), fclose(res);
        printf("===============================================================================\n");
        printf("Solved by simplification\n");
        printStats(S);
        printf("\n");
        printf("UNSATISFIABLE\n");
        exit(20);
    }

    if (dimacs){
        printf("==============================[ Writing DIMACS ]===============================\n");
        S.toDimacs(dimacs);
        printStats(S);
        exit(0);
    }else{
        bool ret = S.solve();
        printStats(S);
        printf("\n");
        printf(ret ? "SATISFIABLE\n" : "UNSATISFIABLE\n");
        if (res != NULL){
            if (ret){
                fprintf(res, "1\n");
                for (int i = 0; i < input_vars.size(); i++){
                    Var inp = input_vars[i];
                    if (S.model[inp] == l_Undef)
                        fprintf(res, "x");
                    else if (S.model[inp] == l_True)
                        fprintf(res, "1");
                    else
                        fprintf(res, "0");
                }
                fprintf(res, "\n");
            }else
                fprintf(res, "0\n");
            fclose(res);
        }
#ifdef NDEBUG
        exit(ret ? 10 : 20);     // (faster than "return", which will invoke the destructor for 'Solver')
#endif
    }
}
<|endoftext|>


<commit_before>/*!
    \file binlog.cpp
    \brief Binary logs reader definition
    \author Ivan Shynkarenka
    \date 16.09.2015
    \copyright MIT License
*/

#include <stdio.h>

#include "logging/record.h"
#include "logging/layouts/text_layout.h"
#include "logging/version.h"

#include <cstring>
#include <iostream>
#include <vector>

#include "../../modules/cpp-optparse/OptionParser.h"

using namespace CppLogging;

bool InputRecord(FILE* input, Record& record)
{
    // Clear the logging record
    record.Clear();

    // Read the logging record size
    uint32_t size;
    if (fread(&size, sizeof(uint32_t), 1, input) != 1)
        return false;

    record.raw.resize(size);

    // Read the logging record raw data
    if (fread(record.raw.data(), 1, size, input) != size)
    {
        std::cerr << "Failed to read from the input file!" << std::endl;
        return false;
    }

    // Get the buffer start position
    const uint8_t* buffer = record.raw.data();

    // Deserialize logging record
    std::memcpy(&record.timestamp, buffer, sizeof(uint64_t));
    buffer += sizeof(uint64_t);
    std::memcpy(&record.thread, buffer, sizeof(uint64_t));
    buffer += sizeof(uint64_t);
    std::memcpy(&record.level, buffer, sizeof(Level));
    buffer += sizeof(Level);

    uint8_t logger_size;
    std::memcpy(&logger_size, buffer, sizeof(uint8_t));
    buffer += sizeof(uint8_t);
    record.logger.insert(record.logger.begin(), buffer, buffer + logger_size);
    buffer += logger_size;

    uint16_t message_size;
    std::memcpy(&message_size, buffer, sizeof(uint16_t));
    buffer += sizeof(uint16_t);
    record.message.insert(record.message.begin(), buffer, buffer + message_size);
    buffer += message_size;

    uint32_t buffer_size;
    std::memcpy(&buffer_size, buffer, sizeof(uint32_t));
    buffer += sizeof(uint32_t);
    record.buffer.insert(record.buffer.begin(), buffer, buffer + buffer_size);
    buffer += buffer_size;

    // Skip the last zero byte
    ++buffer;

    return true;
}

bool OutputRecord(FILE* output, Record& record)
{
    TextLayout layout;
    layout.LayoutRecord(record);

    if (fwrite(record.raw.data(), 1, record.raw.size() - 1, output) != (record.raw.size() - 1))
    {
        std::cerr << "Failed to write into the output file!" << std::endl;
        return false;
    }

    return true;
}

int main(int argc, char** argv)
{
    auto parser = optparse::OptionParser().version(version);

    parser.add_option("-h", "--help").help("Show help");
    parser.add_option("-i", "--input").help("Input file name");
    parser.add_option("-o", "--output").help("Output file name");

    optparse::Values options = parser.parse_args(argc, argv);

    // Print help
    if (options.get("help"))
    {
        parser.print_help();
        parser.exit();
    }

    // Open the input file or stdin
    FILE* input_file = options.is_set("input") ? fopen(options.get("input"), "rb") : stdin;
    if (input_file == nullptr)
    {
        std::cerr << "Failed to open the input file!" << std::endl;
        return -1;
    }

    // Open the output file or stdout
    FILE* output_file = options.is_set("output") ? fopen(options.get("input"), "wb") : stdout;
    if (output_file == nullptr)
    {
        std::cerr << "Failed to open the output file!" << std::endl;
        return -1;
    }

    // Process all logging record
    Record record;
    while (InputRecord(input_file, record))
        if (!OutputRecord(output_file, record))
            break;

    // Close the input file
    if (options.is_set("input"))
    {
        if (fclose(input_file) != 0)
        {
            std::cerr << "Failed to close the input file!" << std::endl;
            return -1;
        }
    }

    // Close the output file
    if (options.is_set("output"))
    {
        if (fclose(output_file) != 0)
        {
            std::cerr << "Failed to close the output file!" << std::endl;
            return -1;
        }
    }

    return 0;
}
<commit_msg>Binlog tool refactoring<commit_after>/*!
    \file binlog.cpp
    \brief Binary logs reader definition
    \author Ivan Shynkarenka
    \date 16.09.2015
    \copyright MIT License
*/

#include <stdio.h>

#include "logging/record.h"
#include "logging/layouts/text_layout.h"
#include "logging/version.h"

#include "filesystem/file.h"
#include "system/stream.h"

#include <cstring>
#include <iostream>
#include <memory>
#include <vector>

#include "../../modules/cpp-optparse/OptionParser.h"

using namespace CppCommon;
using namespace CppLogging;

bool InputRecord(Reader& input, Record& record)
{
    // Clear the logging record
    record.Clear();

    // Read the logging record size
    uint32_t size;
    if (input.Read(&size, sizeof(uint32_t)) != sizeof(uint32_t))
        return false;

    record.raw.resize(size);

    // Read the logging record raw data
    if (input.Read(record.raw.data(), size) != size)
    {
        std::cerr << "Failed to read from the input source!" << std::endl;
        return false;
    }

    // Get the buffer start position
    const uint8_t* buffer = record.raw.data();

    // Deserialize logging record
    std::memcpy(&record.timestamp, buffer, sizeof(uint64_t));
    buffer += sizeof(uint64_t);
    std::memcpy(&record.thread, buffer, sizeof(uint64_t));
    buffer += sizeof(uint64_t);
    std::memcpy(&record.level, buffer, sizeof(Level));
    buffer += sizeof(Level);

    uint8_t logger_size;
    std::memcpy(&logger_size, buffer, sizeof(uint8_t));
    buffer += sizeof(uint8_t);
    record.logger.insert(record.logger.begin(), buffer, buffer + logger_size);
    buffer += logger_size;

    uint16_t message_size;
    std::memcpy(&message_size, buffer, sizeof(uint16_t));
    buffer += sizeof(uint16_t);
    record.message.insert(record.message.begin(), buffer, buffer + message_size);
    buffer += message_size;

    uint32_t buffer_size;
    std::memcpy(&buffer_size, buffer, sizeof(uint32_t));
    buffer += sizeof(uint32_t);
    record.buffer.insert(record.buffer.begin(), buffer, buffer + buffer_size);
    buffer += buffer_size;

    // Skip the last zero byte
    ++buffer;

    return true;
}

bool OutputRecord(Writer& output, Record& record)
{
    TextLayout layout;
    layout.LayoutRecord(record);

    size_t size = record.raw.size() - 1;
    if (output.Write(record.raw.data(), size) != size)
    {
        std::cerr << "Failed to write into the output source!" << std::endl;
        return false;
    }

    return true;
}

int main(int argc, char** argv)
{
    auto parser = optparse::OptionParser().version(version);

    parser.add_option("-h", "--help").help("Show help");
    parser.add_option("-i", "--input").help("Input file name");
    parser.add_option("-o", "--output").help("Output file name");

    optparse::Values options = parser.parse_args(argc, argv);

    // Print help
    if (options.get("help"))
    {
        parser.print_help();
        parser.exit();
    }

    // Open the input file or stdin
    std::unique_ptr<Reader> input(new StdInput());
    if (options.is_set("input"))
    {
        File* file = new File(Path(options.get("input")));
        file->Open(true, false);
        input.reset(file);
    }

    // Open the output file or stdout
    std::unique_ptr<Writer> output(new StdOutput());
    if (options.is_set("output"))
    {
        File* file = new File(Path(options.get("output")));
        file->Open(false, true);
        output.reset(file);
    }

    // Process all logging record
    Record record;
    while (InputRecord(*input, record))
        if (!OutputRecord(*output, record))
            break;

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/options/content_exceptions_window_gtk.h"

#include <set>

#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/content_exception_editor.h"
#include "gfx/gtk_util.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

namespace {

// Singletons for each possible exception window.
ContentExceptionsWindowGtk* instances[CONTENT_SETTINGS_NUM_TYPES] = { NULL };

}  // namespace

// static
void ContentExceptionsWindowGtk::ShowExceptionsWindow(
    GtkWindow* parent,
    HostContentSettingsMap* map,
    ContentSettingsType type) {
  DCHECK(map);
  DCHECK(type < CONTENT_SETTINGS_NUM_TYPES);
  // Geolocation exceptions are handled by GeolocationContentExceptionsWindow.
  DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION);

  if (!instances[type]) {
    // Create the options window.
    instances[type] = new ContentExceptionsWindowGtk(parent, map, type);
  } else {
    gtk_util::PresentWindow(instances[type]->dialog_, 0);
  }
}

ContentExceptionsWindowGtk::~ContentExceptionsWindowGtk() {
}

ContentExceptionsWindowGtk::ContentExceptionsWindowGtk(
    GtkWindow* parent,
    HostContentSettingsMap* map,
    ContentSettingsType type) {
  // Build the model adapters that translate views and TableModels into
  // something GTK can use.
  list_store_ = gtk_list_store_new(COL_COUNT, G_TYPE_STRING, G_TYPE_STRING);
  treeview_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_));
  g_object_unref(list_store_);

  // Set up the properties of the treeview
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_), TRUE);
  g_signal_connect(treeview_, "row-activated",
                   G_CALLBACK(OnTreeViewRowActivateThunk), this);

  GtkTreeViewColumn* pattern_column = gtk_tree_view_column_new_with_attributes(
      l10n_util::GetStringUTF8(IDS_EXCEPTIONS_PATTERN_HEADER).c_str(),
      gtk_cell_renderer_text_new(),
      "text", COL_PATTERN,
      NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), pattern_column);
  gtk_tree_view_column_set_sort_column_id(pattern_column, COL_PATTERN);

  GtkTreeViewColumn* action_column = gtk_tree_view_column_new_with_attributes(
      l10n_util::GetStringUTF8(IDS_EXCEPTIONS_ACTION_HEADER).c_str(),
      gtk_cell_renderer_text_new(),
      "text", COL_ACTION,
      NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), action_column);
  gtk_tree_view_column_set_sort_column_id(action_column, COL_ACTION);

  treeview_selection_ = gtk_tree_view_get_selection(
      GTK_TREE_VIEW(treeview_));
  gtk_tree_selection_set_mode(treeview_selection_, GTK_SELECTION_MULTIPLE);
  g_signal_connect(treeview_selection_, "changed",
                   G_CALLBACK(OnTreeSelectionChangedThunk), this);

  // Bind |list_store_| to our C++ model.
  model_.reset(new ContentExceptionsTableModel(map, type));
  model_adapter_.reset(new gtk_tree::TableAdapter(this, list_store_,
                                                  model_.get()));
  // Force a reload of everything to copy data into |list_store_|.
  model_adapter_->OnModelChanged();

  dialog_ = gtk_dialog_new_with_buttons(
      GetWindowTitle().c_str(),
      parent,
      static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
      GTK_STOCK_CLOSE,
      GTK_RESPONSE_CLOSE,
      NULL);
  gtk_window_set_default_size(GTK_WINDOW(dialog_), 500, -1);
  // Allow browser windows to go in front of the options dialog in metacity.
  gtk_window_set_type_hint(GTK_WINDOW(dialog_), GDK_WINDOW_TYPE_HINT_NORMAL);
  gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
                      gtk_util::kContentAreaSpacing);

  GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), hbox);

  // Create a scrolled window to wrap the treeview widget.
  GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
                                      GTK_SHADOW_ETCHED_IN);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_container_add(GTK_CONTAINER(scrolled), treeview_);
  gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);

  GtkWidget* button_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);

  GtkWidget* add_button = gtk_util::BuildDialogButton(dialog_,
                                                      IDS_EXCEPTIONS_ADD_BUTTON,
                                                      GTK_STOCK_ADD);
  g_signal_connect(add_button, "clicked", G_CALLBACK(AddThunk), this);
  gtk_box_pack_start(GTK_BOX(button_box), add_button, FALSE, FALSE, 0);

  edit_button_ = gtk_util::BuildDialogButton(dialog_,
                                             IDS_EXCEPTIONS_EDIT_BUTTON,
                                             GTK_STOCK_EDIT);
  g_signal_connect(edit_button_, "clicked", G_CALLBACK(EditThunk), this);
  gtk_box_pack_start(GTK_BOX(button_box), edit_button_, FALSE, FALSE, 0);

  remove_button_ = gtk_util::BuildDialogButton(dialog_,
                                               IDS_EXCEPTIONS_REMOVE_BUTTON,
                                               GTK_STOCK_REMOVE);
  g_signal_connect(remove_button_, "clicked", G_CALLBACK(RemoveThunk), this);
  gtk_box_pack_start(GTK_BOX(button_box), remove_button_, FALSE, FALSE, 0);

  remove_all_button_ = gtk_util::BuildDialogButton(
      dialog_,
      IDS_EXCEPTIONS_REMOVEALL_BUTTON,
      GTK_STOCK_CLEAR);
  g_signal_connect(remove_all_button_, "clicked", G_CALLBACK(RemoveAllThunk),
                   this);
  gtk_box_pack_start(GTK_BOX(button_box), remove_all_button_, FALSE, FALSE, 0);

  gtk_box_pack_start(GTK_BOX(hbox), button_box, FALSE, FALSE, 0);

  UpdateButtonState();

  gtk_util::ShowDialogWithLocalizedSize(dialog_,
      IDS_CONTENT_EXCEPTION_DIALOG_WIDTH_CHARS,
      -1,
      true);

  g_signal_connect(dialog_, "response", G_CALLBACK(gtk_widget_destroy), NULL);
  g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroyThunk), this);
}

void ContentExceptionsWindowGtk::SetColumnValues(int row, GtkTreeIter* iter) {
  std::wstring pattern = model_->GetText(row, IDS_EXCEPTIONS_PATTERN_HEADER);
  gtk_list_store_set(list_store_, iter, COL_PATTERN,
                     WideToUTF8(pattern).c_str(), -1);

  std::wstring action = model_->GetText(row, IDS_EXCEPTIONS_ACTION_HEADER);
  gtk_list_store_set(list_store_, iter, COL_ACTION,
                     WideToUTF8(action).c_str(), -1);
}

void ContentExceptionsWindowGtk::AcceptExceptionEdit(
    const HostContentSettingsMap::Pattern& pattern,
    ContentSetting setting,
    int index,
    bool is_new) {
  if (!is_new)
    model_->RemoveException(index);

  model_->AddException(pattern, setting);

  int new_index = model_->IndexOfExceptionByPattern(pattern);
  DCHECK_NE(-1, new_index);

  GtkTreePath* path = gtk_tree_path_new_from_indices(new_index, -1);
  gtk_tree_selection_select_path(treeview_selection_, path);
  gtk_tree_path_free(path);

  UpdateButtonState();
}

void ContentExceptionsWindowGtk::UpdateButtonState() {
  int num_selected = gtk_tree_selection_count_selected_rows(
      treeview_selection_);
  int row_count = gtk_tree_model_iter_n_children(
      GTK_TREE_MODEL(list_store_), NULL);

  // TODO(erg): http://crbug.com/34177 , support editing of more than one entry
  // at a time.
  gtk_widget_set_sensitive(edit_button_, num_selected == 1);
  gtk_widget_set_sensitive(remove_button_, num_selected >= 1);
  gtk_widget_set_sensitive(remove_all_button_, row_count > 0);
}

void ContentExceptionsWindowGtk::Add(GtkWidget* widget) {
  new ContentExceptionEditor(GTK_WINDOW(dialog_),
                             this, model_.get(), -1,
                             HostContentSettingsMap::Pattern(),
                             CONTENT_SETTING_BLOCK);
}

void ContentExceptionsWindowGtk::Edit(GtkWidget* widget) {
  std::set<int> indices;
  gtk_tree::GetSelectedIndices(treeview_selection_, &indices);
  DCHECK_GT(indices.size(), 0u);
  int index = *indices.begin();
  const HostContentSettingsMap::PatternSettingPair& entry =
      model_->entry_at(index);
  new ContentExceptionEditor(GTK_WINDOW(dialog_), this, model_.get(), index,
                             entry.first, entry.second);
}

void ContentExceptionsWindowGtk::Remove(GtkWidget* widget) {
  std::set<int> indices;
  gtk_tree::GetSelectedIndices(treeview_selection_, &indices);

  for (std::set<int>::reverse_iterator i = indices.rbegin();
       i != indices.rend(); ++i) {
    model_->RemoveException(*i);
  }

  UpdateButtonState();
}

void ContentExceptionsWindowGtk::RemoveAll(GtkWidget* widget) {
  model_->RemoveAll();
  UpdateButtonState();
}

std::string ContentExceptionsWindowGtk::GetWindowTitle() const {
  switch (model_->content_type()) {
    case CONTENT_SETTINGS_TYPE_COOKIES:
      return l10n_util::GetStringUTF8(IDS_COOKIE_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_IMAGES:
      return l10n_util::GetStringUTF8(IDS_IMAGES_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
      return l10n_util::GetStringUTF8(IDS_JS_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_PLUGINS:
      return l10n_util::GetStringUTF8(IDS_PLUGINS_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_POPUPS:
      return l10n_util::GetStringUTF8(IDS_POPUP_EXCEPTION_TITLE);
    default:
      NOTREACHED();
  }
  return std::string();
}

void ContentExceptionsWindowGtk::OnTreeViewRowActivate(
    GtkWidget* sender,
    GtkTreePath* path,
    GtkTreeViewColumn* column) {
  Edit(sender);
}

void ContentExceptionsWindowGtk::OnWindowDestroy(GtkWidget* widget) {
  instances[model_->content_type()] = NULL;
  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}

void ContentExceptionsWindowGtk::OnTreeSelectionChanged(
    GtkWidget* selection) {
  UpdateButtonState();
}
<commit_msg>gtk: Improve the usage of Exceptions dialog.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/options/content_exceptions_window_gtk.h"

#include <set>

#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/content_exception_editor.h"
#include "gfx/gtk_util.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

namespace {

// Singletons for each possible exception window.
ContentExceptionsWindowGtk* instances[CONTENT_SETTINGS_NUM_TYPES] = { NULL };

}  // namespace

// static
void ContentExceptionsWindowGtk::ShowExceptionsWindow(
    GtkWindow* parent,
    HostContentSettingsMap* map,
    ContentSettingsType type) {
  DCHECK(map);
  DCHECK(type < CONTENT_SETTINGS_NUM_TYPES);
  // Geolocation exceptions are handled by GeolocationContentExceptionsWindow.
  DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION);

  if (!instances[type]) {
    // Create the options window.
    instances[type] = new ContentExceptionsWindowGtk(parent, map, type);
  } else {
    gtk_util::PresentWindow(instances[type]->dialog_, 0);
  }
}

ContentExceptionsWindowGtk::~ContentExceptionsWindowGtk() {
}

ContentExceptionsWindowGtk::ContentExceptionsWindowGtk(
    GtkWindow* parent,
    HostContentSettingsMap* map,
    ContentSettingsType type) {
  // Build the model adapters that translate views and TableModels into
  // something GTK can use.
  list_store_ = gtk_list_store_new(COL_COUNT, G_TYPE_STRING, G_TYPE_STRING);
  treeview_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_));
  g_object_unref(list_store_);

  // Set up the properties of the treeview
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_), TRUE);
  g_signal_connect(treeview_, "row-activated",
                   G_CALLBACK(OnTreeViewRowActivateThunk), this);

  GtkTreeViewColumn* pattern_column = gtk_tree_view_column_new_with_attributes(
      l10n_util::GetStringUTF8(IDS_EXCEPTIONS_PATTERN_HEADER).c_str(),
      gtk_cell_renderer_text_new(),
      "text", COL_PATTERN,
      NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), pattern_column);
  gtk_tree_view_column_set_sort_column_id(pattern_column, COL_PATTERN);

  GtkTreeViewColumn* action_column = gtk_tree_view_column_new_with_attributes(
      l10n_util::GetStringUTF8(IDS_EXCEPTIONS_ACTION_HEADER).c_str(),
      gtk_cell_renderer_text_new(),
      "text", COL_ACTION,
      NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), action_column);
  gtk_tree_view_column_set_sort_column_id(action_column, COL_ACTION);

  treeview_selection_ = gtk_tree_view_get_selection(
      GTK_TREE_VIEW(treeview_));
  gtk_tree_selection_set_mode(treeview_selection_, GTK_SELECTION_MULTIPLE);
  g_signal_connect(treeview_selection_, "changed",
                   G_CALLBACK(OnTreeSelectionChangedThunk), this);

  // Bind |list_store_| to our C++ model.
  model_.reset(new ContentExceptionsTableModel(map, type));
  model_adapter_.reset(new gtk_tree::TableAdapter(this, list_store_,
                                                  model_.get()));
  // Force a reload of everything to copy data into |list_store_|.
  model_adapter_->OnModelChanged();

  dialog_ = gtk_dialog_new_with_buttons(
      GetWindowTitle().c_str(),
      parent,
      static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
      GTK_STOCK_CLOSE,
      GTK_RESPONSE_CLOSE,
      NULL);
  gtk_window_set_default_size(GTK_WINDOW(dialog_), 500, -1);
  // Allow browser windows to go in front of the options dialog in metacity.
  gtk_window_set_type_hint(GTK_WINDOW(dialog_), GDK_WINDOW_TYPE_HINT_NORMAL);
  gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
                      gtk_util::kContentAreaSpacing);

  GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), hbox);

  // Create a scrolled window to wrap the treeview widget.
  GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
                                      GTK_SHADOW_ETCHED_IN);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_container_add(GTK_CONTAINER(scrolled), treeview_);
  gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);

  GtkWidget* button_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);

  GtkWidget* add_button = gtk_util::BuildDialogButton(dialog_,
                                                      IDS_EXCEPTIONS_ADD_BUTTON,
                                                      GTK_STOCK_ADD);
  g_signal_connect(add_button, "clicked", G_CALLBACK(AddThunk), this);
  gtk_box_pack_start(GTK_BOX(button_box), add_button, FALSE, FALSE, 0);

  edit_button_ = gtk_util::BuildDialogButton(dialog_,
                                             IDS_EXCEPTIONS_EDIT_BUTTON,
                                             GTK_STOCK_EDIT);
  g_signal_connect(edit_button_, "clicked", G_CALLBACK(EditThunk), this);
  gtk_box_pack_start(GTK_BOX(button_box), edit_button_, FALSE, FALSE, 0);

  remove_button_ = gtk_util::BuildDialogButton(dialog_,
                                               IDS_EXCEPTIONS_REMOVE_BUTTON,
                                               GTK_STOCK_REMOVE);
  g_signal_connect(remove_button_, "clicked", G_CALLBACK(RemoveThunk), this);
  gtk_box_pack_start(GTK_BOX(button_box), remove_button_, FALSE, FALSE, 0);

  remove_all_button_ = gtk_util::BuildDialogButton(
      dialog_,
      IDS_EXCEPTIONS_REMOVEALL_BUTTON,
      GTK_STOCK_CLEAR);
  g_signal_connect(remove_all_button_, "clicked", G_CALLBACK(RemoveAllThunk),
                   this);
  gtk_box_pack_start(GTK_BOX(button_box), remove_all_button_, FALSE, FALSE, 0);

  gtk_box_pack_start(GTK_BOX(hbox), button_box, FALSE, FALSE, 0);

  UpdateButtonState();

  gtk_util::ShowDialogWithLocalizedSize(dialog_,
      IDS_CONTENT_EXCEPTION_DIALOG_WIDTH_CHARS,
      -1,
      true);

  g_signal_connect(dialog_, "response", G_CALLBACK(gtk_widget_destroy), NULL);
  g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroyThunk), this);
}

void ContentExceptionsWindowGtk::SetColumnValues(int row, GtkTreeIter* iter) {
  std::wstring pattern = model_->GetText(row, IDS_EXCEPTIONS_PATTERN_HEADER);
  gtk_list_store_set(list_store_, iter, COL_PATTERN,
                     WideToUTF8(pattern).c_str(), -1);

  std::wstring action = model_->GetText(row, IDS_EXCEPTIONS_ACTION_HEADER);
  gtk_list_store_set(list_store_, iter, COL_ACTION,
                     WideToUTF8(action).c_str(), -1);
}

void ContentExceptionsWindowGtk::AcceptExceptionEdit(
    const HostContentSettingsMap::Pattern& pattern,
    ContentSetting setting,
    int index,
    bool is_new) {
  if (!is_new)
    model_->RemoveException(index);

  model_->AddException(pattern, setting);

  int new_index = model_->IndexOfExceptionByPattern(pattern);
  DCHECK_NE(-1, new_index);

  gtk_tree::SelectAndFocusRowNum(new_index, GTK_TREE_VIEW(treeview_));

  UpdateButtonState();
}

void ContentExceptionsWindowGtk::UpdateButtonState() {
  int num_selected = gtk_tree_selection_count_selected_rows(
      treeview_selection_);
  int row_count = gtk_tree_model_iter_n_children(
      GTK_TREE_MODEL(list_store_), NULL);

  // TODO(erg): http://crbug.com/34177 , support editing of more than one entry
  // at a time.
  gtk_widget_set_sensitive(edit_button_, num_selected == 1);
  gtk_widget_set_sensitive(remove_button_, num_selected >= 1);
  gtk_widget_set_sensitive(remove_all_button_, row_count > 0);
}

void ContentExceptionsWindowGtk::Add(GtkWidget* widget) {
  new ContentExceptionEditor(GTK_WINDOW(dialog_),
                             this, model_.get(), -1,
                             HostContentSettingsMap::Pattern(),
                             CONTENT_SETTING_BLOCK);
}

void ContentExceptionsWindowGtk::Edit(GtkWidget* widget) {
  std::set<int> indices;
  gtk_tree::GetSelectedIndices(treeview_selection_, &indices);
  DCHECK_GT(indices.size(), 0u);
  int index = *indices.begin();
  const HostContentSettingsMap::PatternSettingPair& entry =
      model_->entry_at(index);
  new ContentExceptionEditor(GTK_WINDOW(dialog_), this, model_.get(), index,
                             entry.first, entry.second);
}

void ContentExceptionsWindowGtk::Remove(GtkWidget* widget) {
  std::set<int> selected_indices;
  gtk_tree::GetSelectedIndices(treeview_selection_, &selected_indices);

  int selected_row = 0;
  for (std::set<int>::reverse_iterator i = selected_indices.rbegin();
       i != selected_indices.rend(); ++i) {
    model_->RemoveException(*i);
    selected_row = *i;
  }

  int row_count = model_->RowCount();
  if (row_count <= 0)
    return;
  if (selected_row >= row_count)
    selected_row = row_count - 1;
  gtk_tree::SelectAndFocusRowNum(selected_row,
                                 GTK_TREE_VIEW(treeview_));

  UpdateButtonState();
}

void ContentExceptionsWindowGtk::RemoveAll(GtkWidget* widget) {
  model_->RemoveAll();
  UpdateButtonState();
}

std::string ContentExceptionsWindowGtk::GetWindowTitle() const {
  switch (model_->content_type()) {
    case CONTENT_SETTINGS_TYPE_COOKIES:
      return l10n_util::GetStringUTF8(IDS_COOKIE_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_IMAGES:
      return l10n_util::GetStringUTF8(IDS_IMAGES_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
      return l10n_util::GetStringUTF8(IDS_JS_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_PLUGINS:
      return l10n_util::GetStringUTF8(IDS_PLUGINS_EXCEPTION_TITLE);
    case CONTENT_SETTINGS_TYPE_POPUPS:
      return l10n_util::GetStringUTF8(IDS_POPUP_EXCEPTION_TITLE);
    default:
      NOTREACHED();
  }
  return std::string();
}

void ContentExceptionsWindowGtk::OnTreeViewRowActivate(
    GtkWidget* sender,
    GtkTreePath* path,
    GtkTreeViewColumn* column) {
  Edit(sender);
}

void ContentExceptionsWindowGtk::OnWindowDestroy(GtkWidget* widget) {
  instances[model_->content_type()] = NULL;
  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}

void ContentExceptionsWindowGtk::OnTreeSelectionChanged(
    GtkWidget* selection) {
  UpdateButtonState();
}
<|endoftext|>