Import upstream version 0.99.2
[fmit.git] / src / modules / MicrotonalView.cpp
1 // Copyright 2004 "Gilles Degottex"
2
3 // This file is part of "fmit"
4
5 // "fmit" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // "fmit" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19 #include "MicrotonalView.h"
20
21 static const unsigned char g_icon_ji[] = {
22     0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
23     0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
24     0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x05,
25     0xc3, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xb5, 0x97, 0x4b, 0x6c, 0x24,
26     0xc5, 0x19, 0xc7, 0x7f, 0x55, 0xfd, 0x98, 0x5d, 0x7b, 0x1e, 0x1e, 0xdb,
27     0x0c, 0xb3, 0xbb, 0xf6, 0x78, 0xed, 0xf1, 0xda, 0xe0, 0x85, 0x95, 0x80,
28     0x43, 0x88, 0x90, 0x15, 0xb8, 0x70, 0x88, 0xc0, 0x42, 0xe2, 0x86, 0xc4,
29     0x85, 0xa0, 0x58, 0x4a, 0x4e, 0x44, 0x8a, 0x84, 0x72, 0x8a, 0xb4, 0x70,
30     0x08, 0x91, 0x12, 0x5e, 0x97, 0x91, 0x78, 0x48, 0x51, 0x24, 0x94, 0x70,
31     0xca, 0x04, 0x89, 0x03, 0x52, 0x72, 0x18, 0xe5, 0xc4, 0x29, 0x2c, 0x9b,
32     0x08, 0xd6, 0x6b, 0x0f, 0xcc, 0xcb, 0x5e, 0xcf, 0xf8, 0xbd, 0x9e, 0x99,
33     0x6e, 0x4f, 0x17, 0x87, 0xee, 0x9e, 0x99, 0x6e, 0x8f, 0xd7, 0xcb, 0xeb,
34     0x93, 0x4a, 0xdd, 0x35, 0xea, 0xaf, 0xfe, 0xbf, 0xfa, 0x7f, 0x55, 0xd5,
35     0xd3, 0x82, 0x1f, 0x28, 0x16, 0x97, 0x96, 0x47, 0x80, 0x14, 0x70, 0xaf,
36     0x77, 0xed, 0x6f, 0x6d, 0xe0, 0xdd, 0x42, 0x3e, 0x77, 0x3d, 0x9c, 0x27,
37     0xee, 0x72, 0xf0, 0x33, 0xc0, 0x14, 0x30, 0x3d, 0xa0, 0xa5, 0x81, 0x7b,
38     0x00, 0xf3, 0x94, 0x61, 0x1c, 0x20, 0x5b, 0xc8, 0xe7, 0x8a, 0xfd, 0x3f,
39     0xea, 0x21, 0x21, 0x09, 0xfc, 0x04, 0x78, 0x12, 0xb8, 0x14, 0x12, 0x39,
40     0x06, 0x2b, 0x84, 0x20, 0x16, 0x1d, 0x22, 0x1e, 0x1b, 0x26, 0x11, 0x1b,
41     0x26, 0x1e, 0x8b, 0x32, 0x12, 0x8f, 0x12, 0x8f, 0x0d, 0x13, 0x8f, 0x0f,
42     0x93, 0x88, 0x45, 0x11, 0xc0, 0x87, 0xff, 0xfc, 0x17, 0xc5, 0x52, 0x4d,
43     0x02, 0xbf, 0x04, 0x7e, 0x37, 0x10, 0x60, 0x71, 0x69, 0xf9, 0x37, 0xc0,
44     0xcb, 0xde, 0x6c, 0x10, 0x42, 0x30, 0x79, 0x3e, 0xc5, 0xec, 0xcc, 0x24,
45     0xd9, 0x8b, 0x17, 0x18, 0x1f, 0x1d, 0xe9, 0x8a, 0xc4, 0xa3, 0xc3, 0x98,
46     0x67, 0x86, 0x10, 0x7a, 0x84, 0x96, 0xad, 0x68, 0x5a, 0x0e, 0x6d, 0x5b,
47     0xd1, 0xb6, 0x1d, 0x9a, 0x96, 0x43, 0xcb, 0x76, 0x30, 0x34, 0xc9, 0x50,
48     0x44, 0xf2, 0xe8, 0x5c, 0x94, 0xb6, 0x65, 0xf3, 0xe6, 0x3b, 0x7f, 0x07,
49     0x78, 0x2c, 0x3c, 0x09, 0xdd, 0x13, 0xff, 0x2d, 0xf0, 0x1a, 0xc0, 0xc3,
50     0x0f, 0xce, 0xf3, 0xc2, 0x73, 0x4f, 0x73, 0x69, 0x26, 0x83, 0xe5, 0x68,
51     0x34, 0x2d, 0x87, 0x66, 0xbb, 0x43, 0xd3, 0x52, 0x1c, 0x5a, 0x0e, 0xdb,
52     0x6d, 0x87, 0x6a, 0xbd, 0x83, 0xe3, 0x74, 0xe8, 0xa8, 0x43, 0x94, 0x52,
53     0x38, 0x0a, 0x1c, 0xa5, 0x50, 0x0a, 0x1c, 0xc7, 0xef, 0x77, 0x70, 0x1c,
54     0xc5, 0x23, 0x33, 0xc3, 0x3c, 0x70, 0x5f, 0xd6, 0xd7, 0x5b, 0x18, 0x08,
55     0x00, 0x3c, 0x03, 0xf0, 0xb3, 0x9f, 0x3e, 0xc4, 0xd5, 0x97, 0x97, 0x29,
56     0x37, 0x2c, 0xfe, 0x5f, 0xb5, 0xb1, 0x8f, 0xac, 0x9e, 0x00, 0xa0, 0x3c,
57     0x11, 0x1c, 0x9b, 0x8d, 0x5a, 0x8d, 0x6a, 0xa5, 0x42, 0xb5, 0x5a, 0xa1,
58     0x56, 0xad, 0xf0, 0xf3, 0xa5, 0x67, 0x49, 0x9f, 0x9f, 0x70, 0x41, 0x1c,
59     0x17, 0xc8, 0x51, 0x82, 0xa6, 0xe5, 0x90, 0xb9, 0x70, 0xaf, 0xaf, 0x37,
60     0xbe, 0xb8, 0xb4, 0x9c, 0x2a, 0xe4, 0x73, 0xb7, 0xc2, 0x00, 0xa3, 0x00,
61     0x17, 0x33, 0xe7, 0x59, 0xdf, 0xb1, 0x69, 0xec, 0x1f, 0x21, 0x05, 0x98,
62     0x86, 0xc0, 0x51, 0x82, 0x7a, 0xbd, 0xc1, 0xe7, 0xd7, 0x3e, 0xa7, 0x54,
63     0x29, 0x53, 0x2e, 0x95, 0xd9, 0xdc, 0xdc, 0x44, 0x29, 0x05, 0x80, 0x69,
64     0x98, 0x5c, 0x9c, 0x99, 0x21, 0x62, 0x4a, 0x22, 0xba, 0x40, 0x21, 0xe8,
65     0x38, 0x0a, 0xa5, 0x04, 0x8e, 0x82, 0x96, 0xed, 0x90, 0x4a, 0x9c, 0x61,
66     0x6c, 0x34, 0x41, 0x63, 0x6b, 0x17, 0xe0, 0x32, 0x30, 0x18, 0x20, 0x7d,
67     0xcf, 0x28, 0x07, 0xcd, 0x0e, 0xa6, 0x2e, 0x50, 0x4a, 0xa0, 0x70, 0x67,
68     0xb2, 0xb1, 0x5e, 0xe3, 0x1f, 0xf9, 0x3c, 0xa6, 0x61, 0x60, 0xd9, 0x76,
69     0xc0, 0xc2, 0x5f, 0xbc, 0xf8, 0x22, 0x53, 0xd3, 0xd3, 0xae, 0xfd, 0x9e,
70     0x43, 0x4a, 0x09, 0xb7, 0x14, 0x80, 0x7d, 0xe4, 0x82, 0x4e, 0x5d, 0x48,
71     0xfb, 0x00, 0x0b, 0xc0, 0xbf, 0xfd, 0x7c, 0xe9, 0x5d, 0x93, 0x00, 0xe9,
72     0xd4, 0x18, 0xba, 0x26, 0x30, 0x34, 0x81, 0xa1, 0xbb, 0x57, 0x53, 0x13,
73     0x3c, 0x74, 0x65, 0x81, 0x3f, 0xfd, 0xf1, 0x55, 0xde, 0xf8, 0xf3, 0x6b,
74     0x3c, 0x78, 0x39, 0x58, 0xc6, 0x56, 0xf3, 0x36, 0x11, 0x5d, 0x62, 0xea,
75     0x82, 0x88, 0x2e, 0xbb, 0xf7, 0xa6, 0xe1, 0x3a, 0x62, 0x77, 0x5c, 0x80,
76     0xc9, 0x5e, 0x19, 0x2e, 0xf7, 0xe7, 0xfb, 0x00, 0x6d, 0x80, 0xe4, 0x48,
77     0x8c, 0x88, 0xd1, 0x13, 0x37, 0x34, 0x81, 0xae, 0x0b, 0xce, 0x9e, 0x31,
78     0x48, 0xc4, 0x86, 0x31, 0x34, 0xc1, 0xa5, 0xd9, 0x99, 0x00, 0x40, 0xb5,
79     0x5a, 0x71, 0x05, 0x3d, 0x61, 0xa3, 0xef, 0xde, 0xd4, 0x25, 0x1d, 0xc7,
80     0x05, 0xc8, 0x9c, 0x00, 0xe0, 0x97, 0x60, 0x0b, 0x88, 0xb6, 0x5a, 0x16,
81     0xf1, 0xa4, 0x44, 0x29, 0x07, 0x47, 0x81, 0x02, 0xcf, 0xd2, 0x5e, 0xcb,
82     0x4e, 0x4f, 0x06, 0x00, 0xca, 0xa5, 0x12, 0x86, 0x2e, 0x7a, 0xd6, 0xfb,
83     0xbb, 0x41, 0x09, 0x4c, 0x5d, 0x30, 0x16, 0x73, 0x25, 0x32, 0x13, 0x69,
84     0x3f, 0x25, 0x60, 0xa1, 0xef, 0xc0, 0x16, 0xc0, 0xed, 0x66, 0x13, 0x43,
85     0x17, 0x68, 0xd2, 0x73, 0x40, 0xd2, 0x75, 0xc2, 0x77, 0x23, 0x0c, 0xf0,
86     0x75, 0xb9, 0xd2, 0x7b, 0x46, 0x17, 0x18, 0xba, 0x24, 0x76, 0x56, 0x63,
87     0x3a, 0x15, 0xe1, 0xfe, 0x89, 0xb3, 0x8c, 0x0c, 0xeb, 0x61, 0x07, 0xc6,
88     0x17, 0x97, 0x96, 0x53, 0x61, 0x07, 0xb6, 0x01, 0x6e, 0xdf, 0x6e, 0xa2,
89     0x6b, 0x02, 0x5d, 0x73, 0x17, 0x20, 0xfe, 0xcc, 0x7d, 0x27, 0x50, 0x24,
90     0x13, 0x51, 0xc6, 0x46, 0x93, 0x34, 0xb6, 0xb6, 0x01, 0xd8, 0xdf, 0x3f,
91     0x60, 0x7f, 0x6f, 0x87, 0xe4, 0x48, 0x12, 0xd3, 0x10, 0x24, 0x86, 0x74,
92     0x86, 0x22, 0xfe, 0xbc, 0x7a, 0x91, 0x4e, 0x8d, 0x61, 0x9a, 0x06, 0x96,
93     0x65, 0xfb, 0x65, 0xb8, 0x75, 0xdc, 0x81, 0xc3, 0x16, 0x9a, 0x04, 0x5d,
94     0x03, 0x5d, 0x82, 0xa6, 0x09, 0xb7, 0x49, 0x17, 0x4a, 0x97, 0x12, 0x5d,
95     0x1e, 0x77, 0xa1, 0x56, 0xad, 0x92, 0x4e, 0x1a, 0x9c, 0x4b, 0x9a, 0x03,
96     0xc5, 0xc1, 0x3f, 0x59, 0xbb, 0x2e, 0x74, 0xcb, 0x10, 0x2a, 0x41, 0x0b,
97     0x4d, 0x8a, 0x40, 0xd3, 0xa5, 0x40, 0xd7, 0x40, 0x93, 0xa0, 0x69, 0x2e,
98     0xd4, 0x6c, 0x08, 0x60, 0xbd, 0x56, 0x25, 0x62, 0x0c, 0x16, 0xee, 0x8f,
99     0xe9, 0xcc, 0x39, 0xff, 0xb6, 0xbb, 0x10, 0x03, 0x25, 0x38, 0x3c, 0x6c,
100     0x22, 0x05, 0x68, 0x52, 0x74, 0xad, 0x47, 0x29, 0x14, 0xfd, 0x7d, 0x98,
101     0x9b, 0xc9, 0x04, 0x06, 0xfe, 0xf2, 0xe6, 0xd7, 0xa7, 0x8a, 0x03, 0x5c,
102     0x9c, 0x3c, 0x19, 0xa0, 0x0e, 0xb0, 0xb3, 0x77, 0x80, 0x10, 0x02, 0x29,
103     0x14, 0x4a, 0xb8, 0x62, 0x4a, 0xb8, 0x2f, 0x41, 0x1f, 0x40, 0x00, 0x57,
104     0xee, 0x9f, 0x0e, 0x02, 0xac, 0x7e, 0x6b, 0x80, 0x63, 0x25, 0x28, 0x02,
105     0xd4, 0x36, 0xea, 0x08, 0x40, 0x0a, 0x81, 0x26, 0x04, 0x52, 0x0a, 0xa4,
106     0x04, 0x29, 0x40, 0x4a, 0x30, 0x35, 0xc1, 0x50, 0x44, 0x32, 0x3e, 0x1a,
107     0x67, 0x2c, 0x99, 0xe8, 0x0e, 0xbc, 0xd9, 0xd8, 0x61, 0x7b, 0x67, 0xef,
108     0xdb, 0x00, 0x74, 0x77, 0x82, 0x0f, 0xb0, 0x0a, 0x50, 0x5d, 0xaf, 0x23,
109     0x3c, 0x31, 0x21, 0x3c, 0x61, 0x0f, 0xc4, 0xdf, 0x66, 0x7e, 0xcc, 0x65,
110     0x83, 0x65, 0xf8, 0xe2, 0x2e, 0xca, 0x70, 0xe1, 0x5c, 0x0a, 0x5d, 0xd7,
111     0xfc, 0xee, 0xe5, 0x63, 0x00, 0xb5, 0x8d, 0x3a, 0x4a, 0xa9, 0xae, 0x78,
112     0x0f, 0xc2, 0x5d, 0x17, 0xfd, 0x11, 0x06, 0xf8, 0x72, 0xb5, 0x74, 0x2a,
113     0x80, 0xa6, 0xc9, 0xfe, 0xf3, 0x60, 0xa1, 0x0b, 0x50, 0xc8, 0xe7, 0xb6,
114     0x81, 0x1d, 0xcb, 0x3e, 0xa2, 0xb1, 0xb5, 0x8b, 0x40, 0x78, 0x6b, 0xc1,
115     0xbd, 0x86, 0xc5, 0x01, 0xe6, 0x66, 0x82, 0x3b, 0xe1, 0xbb, 0x2e, 0xc4,
116     0xfe, 0xbd, 0xe3, 0x96, 0x61, 0xc3, 0x2d, 0x03, 0x5e, 0x1b, 0xa0, 0x0d,
117     0xc0, 0xfc, 0xec, 0xd4, 0x8f, 0x04, 0xb0, 0xbe, 0x09, 0x3d, 0xfd, 0x13,
118     0x23, 0x35, 0x9e, 0x24, 0x11, 0x8f, 0x76, 0xfb, 0xeb, 0xb7, 0x1a, 0xd4,
119     0xdd, 0xd7, 0xad, 0x7f, 0xda, 0x9d, 0x06, 0xb0, 0x00, 0xc1, 0x3f, 0xa5,
120     0xde, 0x3a, 0x68, 0xdc, 0x79, 0x0a, 0x7d, 0x31, 0x3e, 0x9a, 0x60, 0x77,
121     0xef, 0xa0, 0xdb, 0x7f, 0xfe, 0xd7, 0xbf, 0x47, 0x29, 0xc5, 0xfc, 0xec,
122     0x14, 0x6f, 0xbc, 0xf2, 0xd2, 0xc0, 0x9c, 0x91, 0x44, 0xac, 0x9b, 0xbe,
123     0xb8, 0xb4, 0x9c, 0x3a, 0x06, 0x50, 0xdd, 0xa8, 0x9f, 0x2a, 0xfc, 0xfe,
124     0x07, 0x1f, 0xf1, 0x9f, 0x4f, 0x3f, 0xe3, 0x66, 0xb1, 0xd2, 0xfd, 0xcd,
125     0x34, 0x0d, 0xa6, 0x26, 0xd2, 0xcc, 0x65, 0x33, 0x5c, 0x59, 0xc8, 0x9e,
126     0x98, 0x6b, 0x1a, 0x46, 0xa0, 0xdf, 0x0f, 0xb0, 0x06, 0xbd, 0x12, 0xdc,
127     0x29, 0xfe, 0xfb, 0xbf, 0x1b, 0x44, 0x4c, 0x83, 0x67, 0x9f, 0x7a, 0x82,
128     0xf9, 0x6c, 0x86, 0xb9, 0x6c, 0x86, 0xa9, 0x89, 0x73, 0x68, 0xda, 0x9d,
129     0x8f, 0xe3, 0x8d, 0xcd, 0x2d, 0xde, 0x7e, 0xef, 0x43, 0xbf, 0xdb, 0x2a,
130     0xe4, 0x73, 0xb7, 0xbe, 0x93, 0x03, 0xaf, 0x5f, 0x1d, 0x6c, 0xaf, 0x1f,
131     0x47, 0x47, 0x1d, 0x8a, 0xa5, 0x2a, 0x2b, 0x6b, 0x65, 0x6e, 0xac, 0x95,
132     0xb9, 0xb9, 0x56, 0xe6, 0xc6, 0x5a, 0x89, 0xfd, 0x83, 0xc3, 0xfe, 0xc7,
133     0xfe, 0x0a, 0x41, 0x07, 0xbe, 0x02, 0x3a, 0x8d, 0xad, 0x5d, 0xad, 0x6d,
134     0xd9, 0x44, 0xcc, 0xa0, 0x55, 0x27, 0xc5, 0xee, 0xde, 0x01, 0x2b, 0x45,
135     0x5f, 0xa4, 0xcc, 0xca, 0x5a, 0x99, 0x62, 0xa9, 0x4a, 0xa7, 0xe3, 0x0c,
136     0x7a, 0xbc, 0x09, 0x5c, 0x07, 0xfe, 0x06, 0xbc, 0x09, 0xa1, 0x85, 0xbe,
137     0xb8, 0xb4, 0xbc, 0x0a, 0x4c, 0xbf, 0x7e, 0xf5, 0x25, 0x1e, 0xbe, 0x32,
138     0x1f, 0xc8, 0x74, 0x1c, 0x87, 0xca, 0xfa, 0x26, 0x2b, 0x9e, 0xc8, 0xca,
139     0x5a, 0x89, 0x95, 0xb5, 0x32, 0x9b, 0x8d, 0x9d, 0x93, 0xd8, 0x8a, 0xc0,
140     0x67, 0xa1, 0x76, 0xa3, 0x90, 0xcf, 0x05, 0xc8, 0xf4, 0x50, 0xd2, 0xc7,
141     0xc0, 0xaf, 0xfe, 0xf0, 0xd6, 0x5f, 0x78, 0xf2, 0x89, 0x47, 0xe9, 0x74,
142     0x3a, 0xec, 0xee, 0x1d, 0xb0, 0xfa, 0x55, 0x85, 0x9b, 0xc5, 0x0a, 0xad,
143     0xb6, 0x35, 0x48, 0x68, 0x1f, 0xb8, 0x16, 0x12, 0xba, 0x56, 0xc8, 0xe7,
144     0x4e, 0x7f, 0x39, 0x70, 0xdc, 0x81, 0xf3, 0xc0, 0x27, 0x0c, 0xf8, 0x82,
145     0xc1, 0xfd, 0x36, 0x59, 0x19, 0x30, 0xab, 0x62, 0x21, 0x9f, 0x53, 0x77,
146     0x23, 0x76, 0x2a, 0x80, 0x07, 0x61, 0x02, 0x8f, 0x03, 0x4f, 0x7b, 0xa2,
147     0xbe, 0xd0, 0xf5, 0x42, 0x3e, 0x77, 0x18, 0x7e, 0xfe, 0xfb, 0xc6, 0x37,
148     0xa1, 0xfe, 0x5a, 0x08, 0x89, 0xe7, 0x8c, 0xbc, 0x00, 0x00, 0x00, 0x00,
149     0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
150 };
151
152 #include <cassert>
153 #include <iostream>
154 #include <fstream>
155 #include <sstream>
156 using namespace std;
157 #include <qlayout.h>
158 #include <qpainter.h>
159 #ifdef QT3_SUPPORT
160 #include <q3filedialog.h>
161 #else
162 #include <qfiledialog.h>
163 #endif
164 #include <qmessagebox.h>
165 #include <qregexp.h>
166 #include <qimage.h>
167 #include <qevent.h>
168 #include <qwidgetaction.h>
169 #include <Music/Music.h>
170 using namespace Music;
171
172 // ---------------------- MScale ------------------------------
173
174 void MScale::load_scala(const QString& file_name)
175 {
176         ifstream file(file_name.toAscii().constData());
177
178         if(!file.is_open())
179                 throw MicrotonalView::tr("Unkown filename: '")+file_name+"'";
180
181         int lines_red = 0;
182         int num_line = 1;
183
184         char buff[1024];
185         file.getline(buff, 1024);
186         while(file)
187         {
188                 if(buff[0]!='!')
189                 {
190                         if(lines_red==0)
191                         {
192                                 m_name = QString(buff);
193                                 m_name = m_name.remove("\r");
194                                 m_name = m_name.remove("\n");
195                                 m_name = m_name.simplified();
196                                 lines_red++;
197                         }
198                         else if(lines_red==1)
199                         {
200                                 // ignore number of lines ...
201                                 lines_red++;
202                         }
203                         else
204                         {
205                                 bool is_ratio = true;
206                                 for(size_t i=0; is_ratio && i<strlen(buff); i++)
207                                         is_ratio = buff[i]!='.';
208
209                                 if(is_ratio)
210                                 {
211                                         int num=0, den=0;
212                                         char slash;
213                                         stringstream in(buff);
214                                         in >> num >> slash >> den;
215                                         if(num<0) throw QString("Line ")+QString::number(num_line)+": Parsed numerator is negative '"+QString::number(num)+"'";
216                                         if(slash!='/') throw QString("Line ")+QString::number(num_line)+": There is no slash between numerator and denominator"+slash+"'";
217                                         if(den<=0) throw QString("Line ")+QString::number(num_line)+": Parsed denominator is not positive'"+QString::number(den)+"'";
218                                         values.push_back(MValue(num, den));
219                                 }
220                                 else
221                                 {
222                                         float cents=0.0;
223                                         stringstream in(buff);
224                                         in >> cents;
225                                         if(cents<0.0) throw QString("Line ")+QString::number(num_line)+": Parsed cents value is negative '"+QString::number(cents)+"'";
226                                         values.push_back(MValue(cents));
227                                 }
228                         }
229                 }
230                 file.getline(buff, 1024);
231                 num_line++;
232         }
233 }
234
235 MScale::MScale(const QString& name)
236 : m_name(name)
237 {
238 }
239 MScale::MScale(const QString& file_name, FileType type)
240 {
241         m_path = file_name;
242
243         if(type==SCALA) load_scala(file_name);
244         else
245         {
246                 cerr << "MicrotonalView::Scale::Scale unsupported file type '" << type << "'" << endl;
247         }
248 }
249
250 bool MScale::operator != (const MScale& scale)
251 {
252         return m_name!=scale.m_name;
253 }
254
255 // ---------------------- QRoot button -------------------------
256
257 QRoot::QRoot(MicrotonalView* view, int ht)
258 : QPushButton(view)
259 , m_ht(ht)
260 {
261 //      cerr << "QRoot::QRoot " << m_ht << endl;
262
263 //      if(ht>8) ht+=12;
264
265         connect(this, SIGNAL(clicked()), this, SLOT(clicked2()));
266         connect(this, SIGNAL(rootClicked(int)), view, SLOT(selectRoot(int)));
267         setFlat(true);
268         setText(QString::fromStdString(h2n(ht, GetNotesName(), GetTonality(), false)));
269         setCheckable(true);
270         setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
271         setFixedWidth(35);              // TODO
272         setFocusPolicy(Qt::NoFocus);
273 }
274 void QRoot::clicked2()
275 {
276         emit(rootClicked(m_ht));
277 }
278
279 // --------------------------- MicrotonalView ----------------------------
280
281 MicrotonalView::MicrotonalView(QWidget* parent)
282 : QFrame(parent)
283 , View(tr("Microtonal"), this)
284 , ui_scale_menu(tr("Used scale"), this)
285 {
286         setting_selectedRoot = -1000;
287         m_AFreq = 440.0f;
288         m_selected_jivalue = NULL;
289         m_tuningFreq = 0.0;
290     setting_selectedScale = NULL;
291
292         // settings
293         QPixmap img;
294         img.loadFromData(g_icon_ji, sizeof(g_icon_ji), "PNG");
295         setting_show->setIcon(QIcon(img));
296         setting_show->setChecked(false);
297         hide();
298
299         QHBoxLayout* octaveActionLayout = new QHBoxLayout(&m_popup_menu);
300
301         QLabel* octaveActionTitle = new QLabel(tr("Root's octave"), &m_popup_menu);
302         octaveActionLayout->addWidget(octaveActionTitle);
303
304         setting_octave = new QSpinBox(&m_popup_menu);
305         setting_octave->setMinimum(-3);
306         setting_octave->setMaximum(8);
307         setting_octave->setSingleStep(1);
308         setting_octave->setToolTip(tr("Root's octave"));
309         setting_octave->setValue(3);
310 //      m_old_octave = setting_octave->value();
311 //      connect(setting_octave, SIGNAL(valueChanged(int)), this, SLOT(octaveChanged(int)));
312         connect(setting_octave, SIGNAL(valueChanged(int)), this, SLOT(emitTuningFreqChanged()));
313         octaveActionLayout->addWidget(setting_octave);
314
315         QWidget* octaveActionWidget = new QWidget(&m_popup_menu);
316         octaveActionWidget->setLayout(octaveActionLayout);
317
318         QWidgetAction* octaveAction = new QWidgetAction(&m_popup_menu);
319         octaveAction->setDefaultWidget(octaveActionWidget);
320         m_popup_menu.addAction(octaveAction);
321
322         setting_keepRootToLeft = new QAction(tr("Keep root to left side"), this);
323         setting_keepRootToLeft->setCheckable(true);
324         connect(setting_keepRootToLeft, SIGNAL(toggled(bool)), this, SLOT(keepRootToLeft(bool)));
325         m_popup_menu.addAction(setting_keepRootToLeft);
326
327         setting_loadScale = new QAction(tr("Load Scala file ..."), this);
328         m_popup_menu.addAction(setting_loadScale);
329         connect(setting_loadScale, SIGNAL(activated()), this, SLOT(loadScale()));
330
331         m_popup_menu.addMenu(&ui_scale_menu);
332
333         QVBoxLayout* layout = new QVBoxLayout(this);
334         layout->setMargin(0);
335         layout->setSpacing(0);
336         QHBoxLayout* roots_layout = new QHBoxLayout();
337         roots_layout->setSpacing(0);
338         layout->addLayout(roots_layout);
339         for(int i=0; i<13; i++)
340         {
341                 m_roots.push_back(new QRoot(this, i+3));
342                 roots_layout->addWidget(m_roots.back());
343                 if(i+1<13)
344                         roots_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
345         }
346         m_roots.back()->setDisabled(true);
347         ui_scale = new QScaleLabel(this);
348         layout->addWidget(ui_scale);
349         ui_ratios = new QRatiosLabel(this);
350         layout->addWidget(ui_ratios);
351
352         setMaximumHeight(ui_scale->maximumHeight()+ui_ratios->maximumHeight()+20);
353
354         load_default_scales();
355
356         refreshScaleList();
357
358         selectRoot(3);
359         selectScale(0);
360 }
361 void MicrotonalView::save()
362 {
363         s_settings->setValue("octave", setting_octave->value());
364         s_settings->setValue("keepRootToLeft", setting_keepRootToLeft->isChecked());
365         QStringList scale_list;
366         for(size_t i=0; i<setting_scales.size(); i++)
367                 if(!setting_scales[i]->getPath().isEmpty())
368                         scale_list.push_back(setting_scales[i]->getPath());
369         s_settings->setValue("scales", scale_list);
370         s_settings->setValue("selectedScale", setting_selectedScale->getName());
371         s_settings->setValue("lastScalesDirectory", setting_lastScalesDirectory);
372         s_settings->setValue("selectedRoot", setting_selectedRoot);
373 }
374 void MicrotonalView::load()
375 {
376         setting_octave->setValue(s_settings->value("octave", setting_octave->value()).toInt());
377         setting_keepRootToLeft->setChecked(s_settings->value("keepRootToLeft", setting_keepRootToLeft->isChecked()).toBool());
378         QStringList scale_list = s_settings->value("scales").toStringList();
379         for(QStringList::iterator it=scale_list.begin(); it!=scale_list.end(); ++it)
380         {
381                 try
382                 {
383                         MScale* scale = new MScale(*it, MScale::SCALA);
384                         setting_scales.push_back(scale);
385                 }
386                 catch(QString error){cerr << "MicrotonalView::load " << error.toStdString() << endl;}
387         }
388         refreshScaleList();
389
390         selectScale(s_settings->value("selectedScale", "default").toString());
391         setting_lastScalesDirectory = s_settings->value("lastScalesDirectory", ".").toString();
392         selectRoot(s_settings->value("selectedRoot", m_roots[0]->m_ht).toInt());
393 }
394 void MicrotonalView::clearSettings()
395 {
396         s_settings->remove("octave");
397         s_settings->remove("keepRootToLeft");
398         s_settings->remove("scales");
399         s_settings->remove("selectedScale");
400         s_settings->remove("lastScalesDirectory");
401         s_settings->remove("selectedRoot");
402 }
403
404 /*void MicrotonalView::octaveChanged(int value)
405 {
406         if(value==0)
407         {
408                 if(m_old_octave==1)
409                 {
410                         m_old_octave = -1;
411                         setting_octave->setValue(-1);
412                 }
413                 else if(m_old_octave==-1)
414                 {
415                         m_old_octave = 1;
416                         setting_octave->setValue(1);
417                 }
418         }
419         else
420                 m_old_octave = value;
421 }*/
422
423 int MicrotonalView::getOctaveShift()
424 {
425         return 12*(setting_octave->value()-5);
426 }
427
428 QString MicrotonalView::getTuningNoteName()
429 {
430         if(hasTuningFreqSelected())
431         {
432                 if(m_selected_jivalue->is_ratio)
433                         return QString::fromStdString(h2n(setting_selectedRoot+getOctaveShift()))+":"+QString::number(m_selected_jivalue->num)+"/"+QString::number(m_selected_jivalue->den);
434                 else
435                         return QString::fromStdString(h2n(setting_selectedRoot+getOctaveShift()))+":"+QString::number(m_selected_jivalue->cents);
436         }
437
438         return "no tuning note selected";
439 }
440
441 void MicrotonalView::scaleActionToggled(bool checked)
442 {
443         if (checked)
444                 selectScale(((QAction*)sender())->data().toInt());
445 }
446
447 void MicrotonalView::selectScale(int index)
448 {
449         assert(index>=0 && index<int(setting_scales.size()));
450
451         setting_selectedScale = setting_scales[index];
452
453         QList<QAction*> scaleActions = ui_scale_menu.actions();
454
455         for (int i = 0; i < scaleActions.size(); i++)
456         {
457                 if (i == index)
458                         scaleActions[i]->setChecked(true);
459                 else
460                         scaleActions[i]->setChecked(false);
461         }
462
463         ui_ratios->repaint();
464 }
465 void MicrotonalView::selectScale(const QString& name)
466 {
467         int index = -1;
468         for(size_t i=0; index==-1 && i<setting_scales.size(); i++)
469         {
470                 if(setting_scales[i]->getName()==name)
471                 {
472                         setting_selectedScale = setting_scales[i];
473                         index = i;
474                 }
475         }
476
477         if(index==-1)
478         {
479                 cerr << "MicrotonalView::selectScale unknown scale '" << name.toStdString() << "'" << endl;
480                 return;
481         }
482
483         QList<QAction*> scaleActions = ui_scale_menu.actions();
484
485         for (int i = 0; i < scaleActions.size(); i++)
486         {
487                 if (i == index)
488                         scaleActions[i]->setChecked(true);
489                 else
490                         scaleActions[i]->setChecked(false);
491         }
492
493         ui_ratios->repaint();
494 }
495 int MicrotonalView::getIndex(MScale* scale)
496 {
497         for(size_t i=0; i<setting_scales.size(); i++)
498                 if(setting_scales[i]==scale)
499                         return i;
500
501         return -1;
502 }
503
504 void MicrotonalView::notesNameChanged()
505 {
506         for(int i=0; i<13; i++)
507                 m_roots[i]->setText(QString::fromStdString(h2n(m_roots[i]->m_ht, GetNotesName(), GetTonality(), false)));
508 }
509
510 void MicrotonalView::keepRootToLeft(bool keep)
511 {
512         if(keep)
513         {
514                 for(int i=0; i<13; i++)
515                         m_roots[i]->m_ht = (setting_selectedRoot+i)%12;
516                 notesNameChanged();
517                 selectRoot(setting_selectedRoot);
518                 ui_ratios->repaint();
519         }
520         else
521         {
522         }
523 }
524
525 void MicrotonalView::setAFreq(float AFreq)
526 {
527         float AFreq_old = m_AFreq;
528
529         m_AFreq = AFreq;
530
531         if(m_AFreq!=AFreq_old)
532                 emitTuningFreqChanged();
533 }
534
535 void MicrotonalView::updateCursor(float freq)
536 {
537         ui_scale->m_htf = f2hf(freq, m_AFreq);
538         ui_scale->repaint();
539 }
540
541 void MicrotonalView::selectRoot(int ht)
542 {
543 //      cerr << "MicrotonalView::selectRoot " << ht << endl;
544
545         if(ht==setting_selectedRoot)
546         {
547                 for(int i=0; i<13; i++)
548                         m_roots[i]->setChecked(m_roots[i]->m_ht==ht);
549         }
550         else
551         {
552                 if(setting_keepRootToLeft->isChecked())
553                 {
554                         for(int i=0; i<13; i++)
555                                 m_roots[i]->m_ht = (ht+i)%12;
556                         notesNameChanged();
557                 }
558
559                 for(int i=0; i<13; i++)
560                         m_roots[i]->setChecked(m_roots[i]->m_ht==ht);
561
562                 setting_selectedRoot = ht;
563
564                 ui_ratios->repaint();
565                 emitTuningFreqChanged();
566         }
567 }
568 void MicrotonalView::emitTuningFreqChanged()
569 {
570         m_tuningFreq = 0.0;
571         if(m_selected_jivalue!=NULL)
572         {
573                 if(m_selected_jivalue->is_ratio)
574                         m_tuningFreq = h2f(setting_selectedRoot+getOctaveShift(), m_AFreq)*m_selected_jivalue->ratio;
575                 else
576                         m_tuningFreq = h2f(setting_selectedRoot+getOctaveShift()+m_selected_jivalue->cents/100.0f, m_AFreq);
577         }
578
579         emit(tuningFreqChanged(m_tuningFreq));
580 }
581
582 MicrotonalView::QScaleLabel::QScaleLabel(MicrotonalView* view)
583 : QLabel(view)
584 , ui_view(view)
585 {
586         setMaximumHeight(15);
587         m_htf = -1000.0f;
588 }
589 void MicrotonalView::QScaleLabel::paintEvent(QPaintEvent* event)
590 {
591         QLabel::paintEvent(event);
592
593         QPainter* p = new QPainter(this);
594
595         int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
596         int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
597         int w = right - left;
598         p->setBrush(QColor(255,255,255));
599         p->setPen(QColor(128,128,128));
600         p->drawRect(0, 0, left+1, height());
601         p->drawRect(right, 0, width()-(right+1), height());
602         p->setPen(QColor(0,0,0));
603         p->drawRect(left, 0, w+1, height());
604
605         if(m_htf!=-1000.0)
606         {
607                 float htw = w*(m_htf-ui_view->m_roots[0]->m_ht)/12.0f;
608                 while(htw>=w) htw-=w;
609                 while(htw<0) htw+=w;
610                 int x = int(left+htw);
611                 p->setPen(QColor(0,0,255));
612                 p->setBrush(QColor(191,191,255));
613                 QPolygon polygon(3);
614                 polygon.setPoint(0, x-5, 0);
615                 polygon.setPoint(1, x+5, 0);
616                 polygon.setPoint(2, x, 2*height()/3);
617                 p->drawConvexPolygon(polygon);
618                 p->drawLine(x, 2*height()/3, x, height());
619
620                 if(htw<(w/12.0f)/4.0f || -(htw-w)<(w/12.0f)/4.0f)
621                 {
622                         if(htw<(w/12.0f)/4.0f)  x += w;
623                         else                                    x -= w;
624                         polygon.setPoint(0, x-5, 0);
625                         polygon.setPoint(1, x+5, 0);
626                         polygon.setPoint(2, x, 2*height()/3);
627                         p->drawConvexPolygon(polygon);
628                         p->drawLine(x, 2*height()/3, x, height());
629                 }
630         }
631
632         delete p;
633 }
634
635 MicrotonalView::QRatiosLabel::QRatiosLabel(MicrotonalView* view)
636 : QLabel(view)
637 , ui_view(view)
638 {
639         setMaximumHeight(12+3*(2*fontMetrics().height()+10));
640 }
641 void MicrotonalView::QRatiosLabel::drawTicks(QPainter* p, float r, int h)
642 {
643         int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
644         int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
645         int w = right - left;
646
647         for(float i=r; i<=12.0f; i+=2*r)
648         {
649                 int x = left + int(w*i/12.0f);
650                 p->drawLine(x, 0, x, h);
651         }
652 }
653 void MicrotonalView::QRatiosLabel::paintEvent(QPaintEvent* event)
654 {
655         QLabel::paintEvent(event);
656
657         QPainter* p = new QPainter(this);
658
659         //      p->eraseRect(rect());
660
661         int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
662         int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
663         int w = right - left;
664
665         int tick_height = 12;
666         int max_dec = 3;
667
668         // draw ratios
669         p->setPen(QColor(0,0,255));
670         int dec = 0;
671         int dec_h = 2*p->fontMetrics().height()+2;
672         int dec_h2 = (height()-tick_height-p->fontMetrics().height()+2)/3;
673         dec_h = min(dec_h, dec_h2);
674         int ht = ui_view->setting_selectedRoot - ui_view->m_roots[0]->m_ht;
675         if(ui_view->setting_keepRootToLeft->isChecked())        ht = 0;
676         for(list<MScale::MValue>::iterator it=ui_view->setting_selectedScale->values.begin(); it!=ui_view->setting_selectedScale->values.end(); ++it)
677         {
678                 float htw = 0.0f;
679
680                 if((*it).is_ratio)
681                         htw = w*f2hf(h2f(ht)*(*it).ratio)/12.0f;
682                 else
683                         htw = w*(ht+(*it).cents/100.0f)/12.0f;
684                 while(htw>w) htw-=w;
685                 while(htw<0) htw+=w;
686
687                 int x = left + int(htw);
688                 int y = tick_height + 2 + dec_h*dec;
689                 p->drawLine(x, 0, x, y+dec_h);
690
691                 if((*it).is_ratio)
692                 {
693                         QRect num_rect = fontMetrics().boundingRect(QString::number((*it).num));
694                         num_rect.translate(x+1, y+p->fontMetrics().height());
695                         QRect den_rect = fontMetrics().boundingRect(QString::number((*it).den));
696                         den_rect.translate(x+1, y+2*p->fontMetrics().height());
697                         (*it).bounding_rect = num_rect;
698                         (*it).bounding_rect |= den_rect;
699                 }
700                 else
701                 {
702                         QRect cents_rect = fontMetrics().boundingRect(QString::number((*it).cents));
703                         cents_rect.translate(x+1, y+2*p->fontMetrics().height());
704
705                         (*it).bounding_rect = cents_rect;
706                 }
707                 (*it).bounding_rect.setLeft(x);
708                 (*it).bounding_rect.setRight((*it).bounding_rect.right() + 2);
709                 (*it).bounding_rect.setTop((*it).bounding_rect.top() - 2);
710                 (*it).bounding_rect.setBottom(y+dec_h);
711
712                 if(ui_view->m_selected_jivalue==&(*it))
713                 {
714                         p->setBrush(QColor(210,210,255));
715                         p->drawRect((*it).bounding_rect);
716                 }
717
718                 if((*it).is_ratio)
719                 {
720                         p->drawText(x+1, y+p->fontMetrics().height(), QString::number((*it).num));
721                         p->drawLine(x, y+p->fontMetrics().height()+2, x+p->fontMetrics().width(QString::number((*it).num)), y+p->fontMetrics().height()+2);
722                         p->drawText(x+1, y+2*p->fontMetrics().height(), QString::number((*it).den));
723                 }
724                 else
725                 {
726                         p->drawText(x+1, y+2*p->fontMetrics().height(), QString::number((*it).cents));
727                 }
728
729                 dec++;
730                 if(dec>max_dec-1)       dec = 0;
731                 if(dec<0)                       dec = max_dec-1;
732         }
733
734         // draw ticks
735         p->setPen(QColor(0,0,0));
736         for(float i=0.0f; i<=12.0f; i+=1.0f)
737         {
738                 int x = left + int(w*i/12.0f);
739                 p->drawLine(x, 0, x, tick_height);
740         }
741         drawTicks(p, 0.5f, tick_height/2);
742         drawTicks(p, 0.25f, tick_height/3);
743         drawTicks(p, 0.125f, tick_height/4);
744
745         delete p;
746 }
747
748 void MicrotonalView::mouseReleaseEvent(QMouseEvent* e)
749 {
750         if(e->button()==Qt::LeftButton)
751         {
752                 MScale::MValue* selected_jivalue_old = m_selected_jivalue;
753                 m_selected_jivalue = NULL;
754
755                 QPoint mouse_pos = e->pos() - ui_ratios->pos();
756                 for(list<MScale::MValue>::iterator it=setting_selectedScale->values.begin(); m_selected_jivalue==NULL && it!=setting_selectedScale->values.end(); ++it)
757                         if((*it).bounding_rect.contains(mouse_pos.x(), mouse_pos.y()))
758                                 m_selected_jivalue = &(*it);
759
760                 if(m_selected_jivalue!=selected_jivalue_old)
761                 {
762                         ui_ratios->repaint();
763                         emitTuningFreqChanged();
764                 }
765         }
766
767         View::mouseReleaseEvent(e);
768 }
769
770 void MicrotonalView::refreshScaleList()
771 {
772         ui_scale_menu.clear();
773
774         QActionGroup* scaleGroup = new QActionGroup(this);
775
776         for(size_t i=0; i<setting_scales.size(); i++)
777         {
778                 QAction* scaleAction = ui_scale_menu.addAction(setting_scales[i]->getName());
779                 scaleAction->setCheckable(true);
780                 scaleAction->setData((int)i);
781                 scaleGroup->addAction(scaleAction);
782
783                 if(setting_selectedScale==setting_scales[i])
784                         scaleAction->setChecked(true);
785
786                 connect(scaleAction, SIGNAL(toggled(bool)), this, SLOT(scaleActionToggled(bool)));
787         }
788 }
789 void MicrotonalView::loadScale()
790 {
791 #ifdef QT3_SUPPORT
792         Q3FileDialog dlg_file(setting_lastScalesDirectory, "Scala files (*.scl *.SCL)", this, "open file dialog", true);
793         dlg_file.setCaption(tr("Open scale file"));
794         dlg_file.setMode(Q3FileDialog::ExistingFile);
795         dlg_file.setInfoPreviewEnabled(true);
796         ScalePreview p(&dlg_file);
797         dlg_file.setInfoPreview(&p,&p);
798         dlg_file.setPreviewMode(Q3FileDialog::Info);
799 #else
800         QFileDialog dlg_file(this, tr("Open scale file"), setting_lastScalesDirectory, "Scala files (*.scl *.SCL)");
801         dlg_file.setFileMode(QFileDialog::ExistingFile);
802 #endif
803
804         dlg_file.exec();
805
806         if(dlg_file.result()==QDialog::Accepted)
807         {
808 #ifdef QT3_SUPPORT
809                 setting_lastScalesDirectory = dlg_file.dirPath();
810 #else
811                 setting_lastScalesDirectory = dlg_file.directory().path();
812 #endif
813                 s_settings->setValue("MicrotonalView_lastScalesDirectory", setting_lastScalesDirectory);
814 //              cerr << "setting_lastScalesDirectory=" << setting_lastScalesDirectory << endl;
815                 try
816                 {
817 #ifdef QT3_SUPPORT
818                         MScale* scale = new MScale(dlg_file.selectedFile(), MScale::SCALA);
819 #else
820                         MScale* scale = new MScale(dlg_file.selectedFiles()[0], MScale::SCALA);
821 #endif
822                         bool new_one = true;
823                         for(size_t i=0; new_one && i<setting_scales.size(); i++)
824                                 new_one = *scale != *(setting_scales[i]);
825                         if(new_one)
826                         {
827                                 setting_scales.push_back(scale);
828                                 selectScale(setting_scales.size()-1);
829                                 refreshScaleList();
830                         }
831                         else
832                                 QMessageBox::information(this, tr("Open scale file"), tr("Scale name already exist"), QMessageBox::Ok);
833                 }
834                 catch(QString error)
835                 {
836                         QMessageBox::information(this, tr("Open scale file"), tr("Invalid file content !")+"\n("+error+")", QMessageBox::Ok);
837                 }
838         }
839
840         ui_ratios->repaint();
841 }
842
843 void MicrotonalView::load_default_scales()
844 {
845         MScale* scale = new MScale("default");
846         scale->values.push_back(MScale::MValue(25,24));
847         scale->values.push_back(MScale::MValue(16,15));
848         scale->values.push_back(MScale::MValue(9,8));
849         scale->values.push_back(MScale::MValue(7,6));
850         scale->values.push_back(MScale::MValue(75,64));
851         scale->values.push_back(MScale::MValue(6,5));
852         scale->values.push_back(MScale::MValue(5,4));
853         scale->values.push_back(MScale::MValue(32,25));
854         scale->values.push_back(MScale::MValue(125,96));
855         scale->values.push_back(MScale::MValue(4,3));
856         scale->values.push_back(MScale::MValue(25,18));
857         scale->values.push_back(MScale::MValue(45,32));
858         scale->values.push_back(MScale::MValue(36,25));
859         scale->values.push_back(MScale::MValue(3,2));
860         scale->values.push_back(MScale::MValue(25,16));
861         scale->values.push_back(MScale::MValue(8,5));
862         scale->values.push_back(MScale::MValue(5,3));
863         scale->values.push_back(MScale::MValue(125,72));
864         scale->values.push_back(MScale::MValue(16,9));
865         scale->values.push_back(MScale::MValue(9,5));
866         scale->values.push_back(MScale::MValue(15,8));
867         scale->values.push_back(MScale::MValue(48,25));
868         scale->values.push_back(MScale::MValue(125,64));
869         setting_scales.push_back(scale);
870 }
871
872 // ------------------ MicrotonalView::ScalePreview --------------------
873 #ifdef QT3_SUPPORT
874 MicrotonalView::ScalePreview::ScalePreview(QWidget* parent)
875 : QLabel(parent)
876 {
877         setAlignment(Qt::AlignVCenter);
878         setWordWrap(true);
879         setMinimumWidth(100);
880 }
881 void MicrotonalView::ScalePreview::previewUrl(const Q3Url& url)
882 {
883         if(url.path().contains(QRegExp("\\.scl$"))==0 && url.path().contains(QRegExp("\\.SCL$"))==0)
884         {
885 //              setText("");
886         }
887         else
888         {
889                 try
890                 {
891                         MScale* scale = new MScale(url.path(), MScale::SCALA);
892                         QString txt;
893                         txt += tr("<b>name:</b> ") + scale->getName() + "<p>";
894                         txt += tr("<b>number of ratio:</b> ") + QString::number(scale->values.size());
895                         setText(txt);
896                         delete scale;
897                 }
898                 catch(QString error)
899                 {
900                         setText(tr("Invalid Scala file: ")+error);
901                 }
902         }
903 }
904 #endif