Interfejs

This commit is contained in:
gieb committed 2013-06-15 14:42:57 +02:00
1 parent 750b977d99
commit a0729ff086
1 file changed
+515
+515
View File
@@ -0,0 +1,515 @@
//---------------------------------------------------------------------------------------
// This file is part of the Lomse library.
// Copyright (c) 2010-2013 Cecilio Salmeron. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//
// For any comment, suggestion or feature request, please contact the manager of
// the project at cecilios@users.sourceforge.net
//---------------------------------------------------------------------------------------
// header files required for X11. The order is important:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
//some additional needed stuff
#include <stdio.h>
#include <stdlib.h>
//lomse headers
#include <lomse_doorway.h>
#include <lomse_document.h>
#include <lomse_graphic_view.h>
#include <lomse_interactor.h>
#include <lomse_presenter.h>
#include <lomse_events.h>
using namespace lomse;
//---------------------------------------------------------------------------------------
// In this first example we are just going to display an score on the main window.
// Let's define the necessary variables:
//
LomseDoorway m_lomse; //the Lomse library doorway
Presenter* m_pPresenter; //relates the View, the Document and the Interactor
//the Lomse View renders its content on a bitmap. To manage it, Lomse
//associates the bitmap to a RenderingBuffer object.
//It is your responsibility to render the bitmap on a window.
//Here you define the rendering buffer and its associated bitmap to be
//used by the previously defined View.
RenderingBuffer m_rbuf_window; //Lomse struct to contain the bitmap
unsigned char* m_buf_window; //memory for the bitmap
//some X11 related variables
XImage* m_ximg_window; //the image to display
int m_depth; //color depth
Visual* m_visual; //X11 Visual to use
//Lomse can manage a lot of bitmap formats and pixel formats. You must
//define the format that you are going to use
int m_byte_order; //endian (platform byte ordering)
EPixelFormat m_format; //bitmap format
unsigned m_bpp; //bits per pixel
bool m_flip_y; //true if y axis is reversed
//All typical X stuff needed to run the program and the main events handler loop,
//as well as for handling windows:
Display* m_pDisplay; //points to the X Server.
int m_screen; //refers to which screen of the display to use.
Window m_window; //the actual window itself
GC m_gc; //And the GC is the graphics context.
Atom m_close_atom;
XSetWindowAttributes m_window_attributes;
//some additinal variables
bool m_view_needs_redraw; //to control when the View must be re-drawn
//---------------------------------------------------------------------------------------
void display_view_content(const rendering_buffer* rbuf)
{
if(m_ximg_window == 0) return;
//copy the view bitmap onto the image
m_ximg_window->data = (char*)m_buf_window;
//display the image
XPutImage(m_pDisplay,
m_window,
m_gc,
m_ximg_window,
0, 0, 0, 0,
rbuf->width(),
rbuf->height()
);
}
//---------------------------------------------------------------------------------------
void do_update_window()
{
// Invoking do_update_window() results in just putting immediately the content
// of the currently rendered buffer to the window without neither calling
// any lomse methods nor generating platform related events (i.e. window on_paint)
display_view_content(&m_rbuf_window);
XSync(m_pDisplay, false);
}
//---------------------------------------------------------------------------------------
void update_window(SpEventInfo pEvent)
{
// Callback method for Lomse
do_update_window();
}
//---------------------------------------------------------------------------------------
void open_document()
{
//Normally you will load the content of a file. But in this
//simple example we will create an empty document and define its content
//from a text string
//create a document and get the 'presenter'.
//The Presenter takes care of creating and maintaining all objects
//and relationships between the document, its views and the interactors
//to interact with the view
delete m_pPresenter;
m_pPresenter = m_lomse.new_document(ViewFactory::k_view_vertical_book,
"(lenmusdoc (vers 0.0)"
"(content "
"(para (txt \"Hello world!\"))"
"(score (vers 1.6) "
"(instrument (musicData (clef G)(key C)(time 2 4)(n c4 q) )))"
")"
")" );
//get the pointer to the interactor, set the rendering buffer and register for
//receiving desired events
if (SpInteractor spInteractor = m_pPresenter->get_interactor(0).lock())
{
//connect the View with the window buffer
spInteractor->set_rendering_buffer(&m_rbuf_window);
//ask to receive desired events
spInteractor->add_event_handler(k_update_window_event, update_window);
//hide edition caret
spInteractor->hide_caret();
}
}
//---------------------------------------------------------------------------------------
void update_view_content()
{
//request the view to re-draw the bitmap
if (!m_pPresenter) return;
if (SpInteractor spInteractor = m_pPresenter->get_interactor(0).lock())
spInteractor->redraw_bitmap();
}
//---------------------------------------------------------------------------------------
bool determine_suitable_bitmap_format()
{
//Returns false if we can not find a suitable bitmap format
//for this platform
//determine color depth
m_depth = XDefaultDepth(m_pDisplay, m_screen);
m_visual = XDefaultVisual(m_pDisplay, m_screen);
unsigned long r_mask = m_visual->red_mask;
unsigned long g_mask = m_visual->green_mask;
unsigned long b_mask = m_visual->blue_mask;
if(m_depth < 15 || r_mask == 0 || g_mask == 0 || b_mask == 0)
{
fprintf(stderr,
"There's no Visual compatible with minimal Lomse requirements:\n"
"At least 15-bit color depth and TrueColor or DirectColor class.\n\n");
XCloseDisplay(m_pDisplay);
return false;
}
//determine byte ordering
int t = 1;
int hw_byte_order = LSBFirst;
if(*(char*)&t == 0)
hw_byte_order = MSBFirst;
//use mask to determine the bitmap format to use
switch(m_depth)
{
case 15:
m_bpp = 16;
if(r_mask == 0x7C00 && g_mask == 0x3E0 && b_mask == 0x1F)
{
m_format = k_pix_format_rgb555;
m_byte_order = hw_byte_order;
}
break;
case 16:
m_bpp = 16;
if(r_mask == 0xF800 && g_mask == 0x7E0 && b_mask == 0x1F)
{
m_format = k_pix_format_rgb565;
m_byte_order = hw_byte_order;
}
break;
case 24:
case 32:
m_bpp = 32;
if(g_mask == 0xFF00)
{
if(r_mask == 0xFF && b_mask == 0xFF0000)
{
switch(m_format)
{
case k_pix_format_rgba32:
m_format = k_pix_format_rgba32;
m_byte_order = LSBFirst;
break;
case k_pix_format_abgr32:
m_format = k_pix_format_abgr32;
m_byte_order = MSBFirst;
break;
default:
m_byte_order = hw_byte_order;
m_format =
(hw_byte_order == LSBFirst) ?
k_pix_format_rgba32 :
k_pix_format_abgr32;
break;
}
}
if(r_mask == 0xFF0000 && b_mask == 0xFF)
{
switch(m_format)
{
case k_pix_format_argb32:
m_format = k_pix_format_argb32;
m_byte_order = MSBFirst;
break;
case k_pix_format_bgra32:
m_format = k_pix_format_bgra32;
m_byte_order = LSBFirst;
break;
default:
m_byte_order = hw_byte_order;
m_format =
(hw_byte_order == MSBFirst) ?
k_pix_format_argb32 :
k_pix_format_bgra32;
break;
}
}
}
break;
}
//if no suitable format found, terminate
if(m_format == k_pix_format_undefined)
{
fprintf(stderr,
"RGB masks are not compatible with Lomse pixel formats:\n"
"R=%08lx, R=%08lx, B=%08lx\n", r_mask, g_mask, b_mask);
XCloseDisplay(m_pDisplay);
return false;
}
return true;
}
//---------------------------------------------------------------------------------------
bool create_rendering_buffer(unsigned width, unsigned height, unsigned flags)
{
//allocate memory for the bitmap, fill it with 1's
m_buf_window = new unsigned char[width * height * (m_bpp / 8)];
memset(m_buf_window, 255, width * height * (m_bpp / 8));
//attach this memory to the rendering buffer
m_rbuf_window.attach(m_buf_window, width, height,
(m_flip_y ? -width * (m_bpp / 8) : width * (m_bpp / 8)) );
//create an X11 image using the allocated memory as buffer
m_ximg_window = XCreateImage(m_pDisplay,
m_visual,
m_depth,
ZPixmap,
0,
(char*)m_buf_window,
width,
height,
m_bpp,
width * (m_bpp / 8)
);
m_ximg_window->byte_order = m_byte_order;
//raise flag to redraw window when requested
m_view_needs_redraw = true;
return true;
}
//---------------------------------------------------------------------------------------
void delete_rendering_buffer()
{
delete [] m_buf_window;
if (m_ximg_window)
{
m_ximg_window->data = 0;
XDestroyImage(m_ximg_window);
}
}
//---------------------------------------------------------------------------------------
// application main events handler loop
int handle_events()
{
XFlush(m_pDisplay);
bool quit = false;
while(!quit)
{
if(m_view_needs_redraw)
{
update_view_content();
do_update_window();
m_view_needs_redraw = false;
}
XEvent event;
XNextEvent(m_pDisplay, &event);
switch(event.type)
{
//--------------------------------------------------------------------
case ConfigureNotify:
{
if(event.xconfigure.width != int(m_rbuf_window.width()) ||
event.xconfigure.height != int(m_rbuf_window.height()))
{
int width = event.xconfigure.width;
int height = event.xconfigure.height;
delete_rendering_buffer();
create_rendering_buffer(width, height, 0);
do_update_window();
}
break;
}
//--------------------------------------------------------------------
case Expose:
if (event.xexpose.count == 0)
{
display_view_content(&m_rbuf_window);
XFlush(m_pDisplay);
XSync(m_pDisplay, false);
}
break;
//--------------------------------------------------------------------
case ClientMessage:
if(event.xclient.format == 32
&& event.xclient.data.l[0] == int(m_close_atom) )
{
quit = true;
}
break;
}
}
return 0;
}
//---------------------------------------------------------------------------------------
void define_events_to_process()
{
XSelectInput(m_pDisplay, m_window, ExposureMask | StructureNotifyMask );
}
//---------------------------------------------------------------------------------------
void create_main_window(unsigned width, unsigned height)
{
memset(&m_window_attributes, 0, sizeof(m_window_attributes));
m_window_attributes.border_pixel = XBlackPixel(m_pDisplay, m_screen);
m_window_attributes.background_pixel = XWhitePixel(m_pDisplay, m_screen);
m_window_attributes.override_redirect = 0;
unsigned long window_mask = CWBackPixel | CWBorderPixel;
m_window = XCreateWindow(m_pDisplay,
XDefaultRootWindow(m_pDisplay),
0, 0,
width, height,
0,
m_depth,
InputOutput,
CopyFromParent,
window_mask,
&m_window_attributes
);
//set window title
XSetStandardProperties(m_pDisplay,
m_window,
"Lomse examples. Example_1", //window title
"Lomse_1", //name in tasks bar
None,
NULL,
0,
NULL
);
// create the Graphics Context
m_gc = XCreateGC(m_pDisplay, m_window, 0, 0);
}
//---------------------------------------------------------------------------------------
bool init_x()
{
//returns false if an error occurs
//create X connection
m_pDisplay = XOpenDisplay(NULL);
if(m_pDisplay == 0)
{
fprintf(stderr, "Unable to open DISPLAY!\n");
return false;
}
m_screen = XDefaultScreen(m_pDisplay);
//As lomse renders on a bitmap it is necessary to determine the best
//bitmap format suited for your specific OS and platform
if (!determine_suitable_bitmap_format())
return false;
create_main_window(850, 600); //850 x 600 pixels
create_rendering_buffer(850, 600, 0);
XMapWindow(m_pDisplay, m_window);
m_close_atom = XInternAtom(m_pDisplay, "WM_DELETE_WINDOW", false);
XSetWMProtocols(m_pDisplay, m_window, &m_close_atom, 1);
return true; //no error
};
//---------------------------------------------------------------------------------------
void close_x()
{
XFreeGC(m_pDisplay, m_gc);
XDestroyWindow(m_pDisplay,m_window);
XCloseDisplay(m_pDisplay);
};
//---------------------------------------------------------------------------------------
void initialize_lomse()
{
//initialize the Lomse library
m_flip_y = false; //y axis is not reversed
m_lomse.init_library(m_format, 96, m_flip_y); //resolution=96 ppi
//initialize lomse related variables
m_pPresenter = NULL;
}
//---------------------------------------------------------------------------------------
// application entry point
int main ()
{
if (!init_x())
exit(1);
initialize_lomse();
//create a music score and a View. The view will display the score
//when the paint event is sent to lomse, once the main windows is
//shown and the event handling loop is started
open_document();
//run the main events handling loop
define_events_to_process();
handle_events();
//delete the view and the rendering buffer
delete_rendering_buffer();
delete m_pPresenter; //this will also delete the Doc, the Views and all other stuff
//close X connection
close_x();
return 0;
}