/* * canvas.cpp * * Created: 2009, 2010 * Author: fischer * for use in Yale course CPSC 427a, Fall 2010 * * Derived from: * http://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/drawingarea/clock * subject to the following license: * * gtkmm example Copyright (C) 2002 gtkmm development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "canvas.hpp" #include "clock.hpp" const double Canvas::colorTable[8][4] = { { 0.0, 0.0, 0.0, 1.0 }, // black { 0.6, 0.6, 0.6, 1.0 }, // gray { 1.0, 1.0, 1.0, 0.8 }, // white { 0.9, 0.1, 0.1, 0.8 }, // red { 1.0, 0.6, 0.1, 0.9 }, // orange { 0.9, 0.9, 0.0, 0.9 }, // yellow { 0.34, 0.61, 0.12, 0.9 }, // green { 0.17, 0.39, 0.66, 0.8 } // blue }; Canvas::Canvas(Clock* c) : m_clock(c), m_radius(0.42), m_line_width(0.05) { } bool Canvas::drawClock(Cairo::RefPtr cr, GdkEventExpose* event, double width, double height) { // Get data from model const bool* check = m_clock->getCheck(); const bool blink = m_clock->getBlink(); const time_t lastTime = m_clock->getLastTime(); const bool phase = m_clock->getPhase(); // Set clip region if (event) { // clip to the area indicated by the expose event so that we only // redraw the portion of the window that needs to be redrawn cr->rectangle(event->area.x, event->area.y, event->area.width, event->area.height); cr->clip(); } // Set background size and color // Scale to unit square and translate (0, 0) to be (0.5, 0.5), i.e. // the center of the window cr->scale(width, height); cr->translate(0.5, 0.5); setColor(cr, check[Clock::blue_box] ? blue : gray); cr->paint(); // Draw clock face and lighten center cr->set_line_width(m_line_width); cr->arc(0, 0, m_radius, 0, 2 * M_PI); setColor(cr, white); // white, 80% opaque cr->fill_preserve(); setColor(cr, check[Clock::yellow_box] && (!blink || phase) ? yellow : gray); cr->stroke_preserve(); cr->clip(); // clip subsequent drawing to clock circle // Draw clock ticks cr->set_line_cap(Cairo::LINE_CAP_ROUND); for (int i = 0; i < 12; i++) { double inset; if (i % 3 != 0) { // little tick inset = 0.8 * m_line_width; cr->set_line_width(0.6 * m_line_width); } else { // big tick inset = m_line_width; cr->set_line_width(m_line_width); } cr->move_to((m_radius - inset) * cos(i * M_PI / 6), (m_radius - inset) * sin(i * M_PI / 6)); cr->line_to(m_radius * cos(i * M_PI / 6), m_radius * sin(i * M_PI / 6)); setColor(cr, check[Clock::green_box] && (!blink || phase) ? green : gray); cr->stroke(); } // compute the angles of the indicators of our clock struct tm* lastTimeinfo = localtime(&lastTime); double minutes = lastTimeinfo->tm_min * M_PI / 30; double hours = lastTimeinfo->tm_hour * M_PI / 6; double seconds = lastTimeinfo->tm_sec * M_PI / 30; // draw the hours hand cr->set_line_width(m_line_width); setColor(cr, check[Clock::red_box] ? red : gray); cr->move_to(0, 0); cr->line_to(sin(hours + minutes / 12.0) * (m_radius * 0.5), -cos(hours + minutes / 12.0) * (m_radius * 0.5)); cr->stroke(); // draw the minutes hand setColor(cr, check[Clock::orange_box] ? orange : gray); cr->move_to(0, 0); cr->line_to(sin(minutes + seconds / 60) * (m_radius * 0.8), -cos(minutes + seconds / 60) * (m_radius * 0.8)); cr->stroke(); // draw the seconds hand cr->set_line_width(m_line_width / 3); setColor(cr, gray); cr->move_to(0, 0); cr->line_to(sin(seconds) * (m_radius * 0.9), -cos(seconds) * (m_radius * 0.9)); cr->stroke(); // draw a little dot in the middle setColor(cr, black); cr->arc(0, 0, m_line_width / 3.0, 0, 2 * M_PI); cr->fill(); return true; } bool Canvas::on_expose_event(GdkEventExpose* event) { // This is where we draw on the window Glib::RefPtr window = get_window(); if (window) { Gtk::Allocation allocation = get_allocation(); const int width = allocation.get_width(); const int height = allocation.get_height(); drawClock(window->create_cairo_context(), event, width, height); } return true; } // force our program to redraw the entire clock. void Canvas::forceRedraw() { Glib::RefPtr win = get_window(); if (win) { Gdk::Rectangle r(0, 0, get_allocation().get_width(), get_allocation().get_height()); win->invalidate_rect(r, false); } }