vinace/src/gui/c-gui-disk-drive.cpp

196 lines
6.1 KiB
C++

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
* Vinace
* Copyright (C) P.Y. Rollo 2009 <dev@pyrollo.com>
*
* Vinace is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Vinace 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, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include "c-gui-disk-drive.hpp"
/* Pictures:
*
* The hole picture size is 300x178
* The "open" picture is 79x123 and should be placed at 110,16
* The "on" picture is 18x18 and should be placed at 56,120
*/
bool in_rect(int x, int y, Gdk::Rectangle *rect) {
return
(x>=rect->get_x() and
x<=(rect->get_x()+rect->get_width()) and
y>=rect->get_y() and
y<=(rect->get_y()+rect->get_height()));
};
#define IMAGE_DRIVE_1 "resources/drive_1.jpg"
#define IMAGE_DRIVE_2 "resources/drive_2.jpg"
#define IMAGE_CLOSED "resources/closed.jpg"
#define IMAGE_ON "resources/on.jpg"
#define PIX_ON_X (63)
#define PIX_ON_Y (140)
#define PIX_CLOSED_X (129)
#define PIX_CLOSED_Y (20)
CGuiDiskDrive::CGuiDiskDrive(CDiskDrive *drive, bool drive2) {
this->drive = drive;
this->disk = new CFloppyDisk(); // Blank disk
this->motor_on = drive->get_motor();
this->loaded = drive->loaded();
// Pixbuf preparation
if (drive2)
mainpix = Gdk::Pixbuf::create_from_file(IMAGE_DRIVE_2);
else
mainpix = Gdk::Pixbuf::create_from_file(IMAGE_DRIVE_1);
closedpix = Gdk::Pixbuf::create_from_file(IMAGE_CLOSED);
closedrect = new Gdk::Rectangle(PIX_CLOSED_X, PIX_CLOSED_Y, closedpix->get_width(), closedpix->get_height());
onpix = Gdk::Pixbuf::create_from_file(IMAGE_ON);
onrect = new Gdk::Rectangle(PIX_ON_X, PIX_ON_Y, onpix->get_width(), onpix->get_height());
pressed_rect = 0;
// Text layout for displaying disk name
layout_disk_name = create_pango_layout("disk name");
layout_disk_name->set_text(disk->get_name());
layout_disk_name->set_alignment(Pango::ALIGN_CENTER);
layout_disk_name->set_width(mainpix->get_width()*PANGO_SCALE);
// Adjust drawing area size
set_size_request(mainpix->get_width(), mainpix->get_height());
signal_expose_event().connect(sigc::mem_fun(this, &CGuiDiskDrive::on_expose_event));
// Signals for clicking
signal_button_press_event().connect(sigc::mem_fun(this, &CGuiDiskDrive::button_press));
signal_button_release_event().connect(sigc::mem_fun(this, &CGuiDiskDrive::button_release));
add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
// Become a Drag and Drop destination
signal_drag_data_received().connect(sigc::mem_fun(this, &CGuiDiskDrive::on_drag_data_received));
drag_dest_set(Gtk::DestDefaults(), Gdk::DragAction());
signal_drag_drop().connect(sigc::mem_fun(this, &CGuiDiskDrive::on_drag_drop));
signal_drag_motion().connect(sigc::mem_fun(this, &CGuiDiskDrive::on_drag_motion));
// Observe the drive
drive->subscribe(this);
}
CGuiDiskDrive::~CGuiDiskDrive() {
drive->unsubscribe(this);
delete closedrect;
delete onrect;
if (disk) delete disk;
}
void CGuiDiskDrive::notify(CObservable *obs) {
if (obs == drive) {
// Has a disk been ejected or loaded ?
if (drive->loaded() != loaded) {
this->loaded = drive->loaded();
if (get_window())
get_window()->invalidate_rect(*closedrect, false);
}
// Has the motor been switched ?
if (drive->get_motor() != motor_on) {
this->motor_on = drive->get_motor();
if (get_window())
get_window()->invalidate_rect(*onrect, false);
}
}
}
void CGuiDiskDrive::load_disk(std::string filename) {
delete disk;
disk = new CFloppyDisk(filename);
drive->eject();
drive->insert(disk);
layout_disk_name->set_text(disk->get_name());
get_window()->invalidate_region(get_window()->get_visible_region()); // A bit brutal but changing disk wont append so often
}
void CGuiDiskDrive::on_drag_data_received(
const Glib::RefPtr<Gdk::DragContext>& context, int, int,
const Gtk::SelectionData& selection_data, guint, guint time)
{
Glib::StringArrayHandle uris = selection_data.get_uris();
if (uris.size() == 1) {
Glib::ustring url = *(uris.begin());
if (url.substr(0,7) == "file://") {
load_disk(Glib::uri_unescape_string(url.substr(7).raw()));
context->drop_finish(true, time);
return;
}
}
context->drop_finish(false, time);
}
bool CGuiDiskDrive::on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context,
int, int, guint time) {
drag_get_data(context, "text/uri-list", time);
}
bool CGuiDiskDrive::on_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context,
int, int, guint time) {
context->drag_status(Gdk::ACTION_COPY, time);
}
//http://gtk.php.net/manual1/fr/html/gdk.gdkeventbutton.html
bool CGuiDiskDrive::button_press(GdkEventButton* event) {
int x = (int)event->x;
int y = (int)event->y;
if (in_rect(x, y, closedrect)) {
pressed_rect = closedrect;
}
}
bool CGuiDiskDrive::button_release(GdkEventButton* event) {
int x = (int)event->x;
int y = (int)event->y;
if (event->button == 1
and in_rect(x, y, closedrect)
and pressed_rect == closedrect)
{
if (loaded)
drive->eject();
else
drive->insert(disk);
get_window()->invalidate_rect(*closedrect, false);
}
pressed_rect = 0;
}
bool CGuiDiskDrive::on_expose_event(GdkEventExpose* ev)
{
if (get_window()) {
mainpix->render_to_drawable(get_window(), get_style()->get_black_gc(), 0, 0, 0, 0, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0);
if (motor_on)
onpix->render_to_drawable(get_window(), get_style()->get_black_gc(), 0, 0, PIX_ON_X, PIX_ON_Y, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0);
if (loaded)
closedpix->render_to_drawable(get_window(), get_style()->get_black_gc(), 0, 0, PIX_CLOSED_X, PIX_CLOSED_Y, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0);
get_window()->draw_layout(get_style()->get_white_gc(), 0, mainpix->get_height() - 30, layout_disk_name);
}
return true;
}