code format
This commit is contained in:
+572
-593
@@ -29,10 +29,10 @@
|
||||
#ifndef gif_h
|
||||
#define gif_h
|
||||
|
||||
#include <stdbool.h> // for bool macros
|
||||
#include <stdint.h> // for integer typedefs
|
||||
#include <stdio.h> // for FILE*
|
||||
#include <string.h> // for memcpy and bzero
|
||||
#include <stdint.h> // for integer typedefs
|
||||
#include <stdbool.h> // for bool macros
|
||||
|
||||
// Define these macros to hook into a custom memory allocator.
|
||||
// TEMP_MALLOC and TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs
|
||||
@@ -41,796 +41,775 @@
|
||||
// is used to find changed pixels for delta-encoding.)
|
||||
|
||||
#ifndef GIF_TEMP_MALLOC
|
||||
#include <stdlib.h>
|
||||
#define GIF_TEMP_MALLOC malloc
|
||||
# include <stdlib.h>
|
||||
# define GIF_TEMP_MALLOC malloc
|
||||
#endif
|
||||
|
||||
#ifndef GIF_TEMP_FREE
|
||||
#include <stdlib.h>
|
||||
#define GIF_TEMP_FREE free
|
||||
# include <stdlib.h>
|
||||
# define GIF_TEMP_FREE free
|
||||
#endif
|
||||
|
||||
#ifndef GIF_MALLOC
|
||||
#include <stdlib.h>
|
||||
#define GIF_MALLOC malloc
|
||||
# include <stdlib.h>
|
||||
# define GIF_MALLOC malloc
|
||||
#endif
|
||||
|
||||
#ifndef GIF_FREE
|
||||
#include <stdlib.h>
|
||||
#define GIF_FREE free
|
||||
# include <stdlib.h>
|
||||
# define GIF_FREE free
|
||||
#endif
|
||||
|
||||
const int kGifTransIndex = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int bitDepth;
|
||||
typedef struct {
|
||||
int bitDepth;
|
||||
|
||||
uint8_t r[256];
|
||||
uint8_t g[256];
|
||||
uint8_t b[256];
|
||||
uint8_t r[256];
|
||||
uint8_t g[256];
|
||||
uint8_t b[256];
|
||||
|
||||
// k-d tree over RGB space, organized in heap fashion
|
||||
// i.e. left child of node i is node i*2, right child is node i*2+1
|
||||
// nodes 256-511 are implicitly the leaves, containing a color
|
||||
uint8_t treeSplitElt[256];
|
||||
uint8_t treeSplit[256];
|
||||
// k-d tree over RGB space, organized in heap fashion
|
||||
// i.e. left child of node i is node i*2, right child is node i*2+1
|
||||
// nodes 256-511 are implicitly the leaves, containing a color
|
||||
uint8_t treeSplitElt[256];
|
||||
uint8_t treeSplit[256];
|
||||
} GifPalette;
|
||||
|
||||
// max, min, and abs functions
|
||||
int GifIMax(int l, int r) { return l>r?l:r; }
|
||||
int GifIMin(int l, int r) { return l<r?l:r; }
|
||||
int GifIAbs(int i) { return i<0?-i:i; }
|
||||
int GifIMax(int l, int r) {
|
||||
return l > r ? l : r;
|
||||
}
|
||||
int GifIMin(int l, int r) {
|
||||
return l < r ? l : r;
|
||||
}
|
||||
int GifIAbs(int i) {
|
||||
return i < 0 ? -i : i;
|
||||
}
|
||||
|
||||
// walks the k-d tree to pick the palette entry for a desired color.
|
||||
// Takes as in/out parameters the current best color and its error -
|
||||
// only changes them if it finds a better color in its subtree.
|
||||
// this is the major hotspot in the code at the moment.
|
||||
void GifGetClosestPaletteColor( GifPalette* pPal, int r, int g, int b, int* bestInd, int* bestDiff, int treeRoot )
|
||||
{
|
||||
// base case, reached the bottom of the tree
|
||||
if(treeRoot > (1<<pPal->bitDepth)-1)
|
||||
{
|
||||
int ind = treeRoot-(1<<pPal->bitDepth);
|
||||
if(ind == kGifTransIndex) return;
|
||||
void GifGetClosestPaletteColor(GifPalette * pPal, int r, int g, int b, int * bestInd, int * bestDiff, int treeRoot) {
|
||||
// base case, reached the bottom of the tree
|
||||
if (treeRoot > (1 << pPal->bitDepth) - 1) {
|
||||
int ind = treeRoot - (1 << pPal->bitDepth);
|
||||
if (ind == kGifTransIndex) return;
|
||||
|
||||
// check whether this color is better than the current winner
|
||||
int r_err = r - ((int32_t)pPal->r[ind]);
|
||||
int g_err = g - ((int32_t)pPal->g[ind]);
|
||||
int b_err = b - ((int32_t)pPal->b[ind]);
|
||||
int diff = GifIAbs(r_err)+GifIAbs(g_err)+GifIAbs(b_err);
|
||||
// check whether this color is better than the current winner
|
||||
int r_err = r - ((int32_t)pPal->r[ind]);
|
||||
int g_err = g - ((int32_t)pPal->g[ind]);
|
||||
int b_err = b - ((int32_t)pPal->b[ind]);
|
||||
int diff = GifIAbs(r_err) + GifIAbs(g_err) + GifIAbs(b_err);
|
||||
|
||||
if(diff < *bestDiff)
|
||||
{
|
||||
*bestInd = ind;
|
||||
*bestDiff = diff;
|
||||
}
|
||||
if (diff < *bestDiff) {
|
||||
*bestInd = ind;
|
||||
*bestDiff = diff;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// take the appropriate color (r, g, or b) for this node of the k-d tree
|
||||
int comps[3]; comps[0] = r; comps[1] = g; comps[2] = b;
|
||||
int splitComp = comps[pPal->treeSplitElt[treeRoot]];
|
||||
// take the appropriate color (r, g, or b) for this node of the k-d tree
|
||||
int comps[3];
|
||||
comps[0] = r;
|
||||
comps[1] = g;
|
||||
comps[2] = b;
|
||||
int splitComp = comps[pPal->treeSplitElt[treeRoot]];
|
||||
|
||||
int splitPos = pPal->treeSplit[treeRoot];
|
||||
if(splitPos > splitComp)
|
||||
{
|
||||
// check the left subtree
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
if( *bestDiff > splitPos - splitComp )
|
||||
{
|
||||
// cannot prove there's not a better value in the right subtree, check that too
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1);
|
||||
if( *bestDiff > splitComp - splitPos )
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
}
|
||||
}
|
||||
int splitPos = pPal->treeSplit[treeRoot];
|
||||
if (splitPos > splitComp) {
|
||||
// check the left subtree
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2);
|
||||
if (*bestDiff > splitPos - splitComp) {
|
||||
// cannot prove there's not a better value in the right subtree, check that too
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1);
|
||||
}
|
||||
} else {
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1);
|
||||
if (*bestDiff > splitComp - splitPos) {
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GifSwapPixels(uint8_t* image, int pixA, int pixB)
|
||||
{
|
||||
uint8_t rA = image[pixA*4];
|
||||
uint8_t gA = image[pixA*4+1];
|
||||
uint8_t bA = image[pixA*4+2];
|
||||
uint8_t aA = image[pixA*4+3];
|
||||
void GifSwapPixels(uint8_t * image, int pixA, int pixB) {
|
||||
uint8_t rA = image[pixA * 4];
|
||||
uint8_t gA = image[pixA * 4 + 1];
|
||||
uint8_t bA = image[pixA * 4 + 2];
|
||||
uint8_t aA = image[pixA * 4 + 3];
|
||||
|
||||
uint8_t rB = image[pixB*4];
|
||||
uint8_t gB = image[pixB*4+1];
|
||||
uint8_t bB = image[pixB*4+2];
|
||||
uint8_t aB = image[pixA*4+3];
|
||||
uint8_t rB = image[pixB * 4];
|
||||
uint8_t gB = image[pixB * 4 + 1];
|
||||
uint8_t bB = image[pixB * 4 + 2];
|
||||
uint8_t aB = image[pixA * 4 + 3];
|
||||
|
||||
image[pixA*4] = rB;
|
||||
image[pixA*4+1] = gB;
|
||||
image[pixA*4+2] = bB;
|
||||
image[pixA*4+3] = aB;
|
||||
image[pixA * 4] = rB;
|
||||
image[pixA * 4 + 1] = gB;
|
||||
image[pixA * 4 + 2] = bB;
|
||||
image[pixA * 4 + 3] = aB;
|
||||
|
||||
image[pixB*4] = rA;
|
||||
image[pixB*4+1] = gA;
|
||||
image[pixB*4+2] = bA;
|
||||
image[pixB*4+3] = aA;
|
||||
image[pixB * 4] = rA;
|
||||
image[pixB * 4 + 1] = gA;
|
||||
image[pixB * 4 + 2] = bA;
|
||||
image[pixB * 4 + 3] = aA;
|
||||
}
|
||||
|
||||
// just the partition operation from quicksort
|
||||
int GifPartition(uint8_t* image, const int left, const int right, const int elt, int pivotIndex)
|
||||
{
|
||||
const int pivotValue = image[(pivotIndex)*4+elt];
|
||||
GifSwapPixels(image, pivotIndex, right-1);
|
||||
int storeIndex = left;
|
||||
bool split = 0;
|
||||
for(int ii=left; ii<right-1; ++ii)
|
||||
{
|
||||
int arrayVal = image[ii*4+elt];
|
||||
if( arrayVal < pivotValue )
|
||||
{
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
}
|
||||
else if( arrayVal == pivotValue )
|
||||
{
|
||||
if(split)
|
||||
{
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
}
|
||||
split = !split;
|
||||
}
|
||||
}
|
||||
GifSwapPixels(image, storeIndex, right-1);
|
||||
return storeIndex;
|
||||
int GifPartition(uint8_t * image, const int left, const int right, const int elt, int pivotIndex) {
|
||||
const int pivotValue = image[(pivotIndex)*4 + elt];
|
||||
GifSwapPixels(image, pivotIndex, right - 1);
|
||||
int storeIndex = left;
|
||||
bool split = 0;
|
||||
for (int ii = left; ii < right - 1; ++ii) {
|
||||
int arrayVal = image[ii * 4 + elt];
|
||||
if (arrayVal < pivotValue) {
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
} else if (arrayVal == pivotValue) {
|
||||
if (split) {
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
}
|
||||
split = !split;
|
||||
}
|
||||
}
|
||||
GifSwapPixels(image, storeIndex, right - 1);
|
||||
return storeIndex;
|
||||
}
|
||||
|
||||
// Perform an incomplete sort, finding all elements above and below the desired median
|
||||
void GifPartitionByMedian(uint8_t* image, int left, int right, int com, int neededCenter)
|
||||
{
|
||||
if(left < right-1)
|
||||
{
|
||||
int pivotIndex = left + (right-left)/2;
|
||||
void GifPartitionByMedian(uint8_t * image, int left, int right, int com, int neededCenter) {
|
||||
if (left < right - 1) {
|
||||
int pivotIndex = left + (right - left) / 2;
|
||||
|
||||
pivotIndex = GifPartition(image, left, right, com, pivotIndex);
|
||||
pivotIndex = GifPartition(image, left, right, com, pivotIndex);
|
||||
|
||||
// Only "sort" the section of the array that contains the median
|
||||
if(pivotIndex > neededCenter)
|
||||
GifPartitionByMedian(image, left, pivotIndex, com, neededCenter);
|
||||
// Only "sort" the section of the array that contains the median
|
||||
if (pivotIndex > neededCenter) GifPartitionByMedian(image, left, pivotIndex, com, neededCenter);
|
||||
|
||||
if(pivotIndex < neededCenter)
|
||||
GifPartitionByMedian(image, pivotIndex+1, right, com, neededCenter);
|
||||
}
|
||||
if (pivotIndex < neededCenter) GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter);
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a palette by creating a balanced k-d tree of all pixels in the image
|
||||
void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette* pal)
|
||||
{
|
||||
if(lastElt <= firstElt || numPixels == 0)
|
||||
return;
|
||||
void GifSplitPalette(uint8_t * image,
|
||||
int numPixels,
|
||||
int firstElt,
|
||||
int lastElt,
|
||||
int splitElt,
|
||||
int splitDist,
|
||||
int treeNode,
|
||||
bool buildForDither,
|
||||
GifPalette * pal) {
|
||||
if (lastElt <= firstElt || numPixels == 0) return;
|
||||
|
||||
// base case, bottom of the tree
|
||||
if(lastElt == firstElt+1)
|
||||
{
|
||||
if(buildForDither)
|
||||
{
|
||||
// Dithering needs at least one color as dark as anything
|
||||
// in the image and at least one brightest color -
|
||||
// otherwise it builds up error and produces strange artifacts
|
||||
if( firstElt == 1 )
|
||||
{
|
||||
// special case: the darkest color in the image
|
||||
uint32_t r=255, g=255, b=255;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r = (uint32_t)GifIMin((int32_t)r, image[ii * 4 + 0]);
|
||||
g = (uint32_t)GifIMin((int32_t)g, image[ii * 4 + 1]);
|
||||
b = (uint32_t)GifIMin((int32_t)b, image[ii * 4 + 2]);
|
||||
}
|
||||
// base case, bottom of the tree
|
||||
if (lastElt == firstElt + 1) {
|
||||
if (buildForDither) {
|
||||
// Dithering needs at least one color as dark as anything
|
||||
// in the image and at least one brightest color -
|
||||
// otherwise it builds up error and produces strange artifacts
|
||||
if (firstElt == 1) {
|
||||
// special case: the darkest color in the image
|
||||
uint32_t r = 255, g = 255, b = 255;
|
||||
for (int ii = 0; ii < numPixels; ++ii) {
|
||||
r = (uint32_t)GifIMin((int32_t)r, image[ii * 4 + 0]);
|
||||
g = (uint32_t)GifIMin((int32_t)g, image[ii * 4 + 1]);
|
||||
b = (uint32_t)GifIMin((int32_t)b, image[ii * 4 + 2]);
|
||||
}
|
||||
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( firstElt == (1 << pal->bitDepth)-1 )
|
||||
{
|
||||
// special case: the lightest color in the image
|
||||
uint32_t r=0, g=0, b=0;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r = (uint32_t)GifIMax((int32_t)r, image[ii * 4 + 0]);
|
||||
g = (uint32_t)GifIMax((int32_t)g, image[ii * 4 + 1]);
|
||||
b = (uint32_t)GifIMax((int32_t)b, image[ii * 4 + 2]);
|
||||
}
|
||||
if (firstElt == (1 << pal->bitDepth) - 1) {
|
||||
// special case: the lightest color in the image
|
||||
uint32_t r = 0, g = 0, b = 0;
|
||||
for (int ii = 0; ii < numPixels; ++ii) {
|
||||
r = (uint32_t)GifIMax((int32_t)r, image[ii * 4 + 0]);
|
||||
g = (uint32_t)GifIMax((int32_t)g, image[ii * 4 + 1]);
|
||||
b = (uint32_t)GifIMax((int32_t)b, image[ii * 4 + 2]);
|
||||
}
|
||||
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, take the average of all colors in this subcube
|
||||
uint64_t r=0, g=0, b=0;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r += image[ii*4+0];
|
||||
g += image[ii*4+1];
|
||||
b += image[ii*4+2];
|
||||
}
|
||||
// otherwise, take the average of all colors in this subcube
|
||||
uint64_t r = 0, g = 0, b = 0;
|
||||
for (int ii = 0; ii < numPixels; ++ii) {
|
||||
r += image[ii * 4 + 0];
|
||||
g += image[ii * 4 + 1];
|
||||
b += image[ii * 4 + 2];
|
||||
}
|
||||
|
||||
r += (uint64_t)numPixels / 2; // round to nearest
|
||||
g += (uint64_t)numPixels / 2;
|
||||
b += (uint64_t)numPixels / 2;
|
||||
r += (uint64_t)numPixels / 2; // round to nearest
|
||||
g += (uint64_t)numPixels / 2;
|
||||
b += (uint64_t)numPixels / 2;
|
||||
|
||||
r /= (uint64_t)numPixels;
|
||||
g /= (uint64_t)numPixels;
|
||||
b /= (uint64_t)numPixels;
|
||||
r /= (uint64_t)numPixels;
|
||||
g /= (uint64_t)numPixels;
|
||||
b /= (uint64_t)numPixels;
|
||||
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the axis with the largest range
|
||||
int minR = 255, maxR = 0;
|
||||
int minG = 255, maxG = 0;
|
||||
int minB = 255, maxB = 0;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
int r = image[ii*4+0];
|
||||
int g = image[ii*4+1];
|
||||
int b = image[ii*4+2];
|
||||
// Find the axis with the largest range
|
||||
int minR = 255, maxR = 0;
|
||||
int minG = 255, maxG = 0;
|
||||
int minB = 255, maxB = 0;
|
||||
for (int ii = 0; ii < numPixels; ++ii) {
|
||||
int r = image[ii * 4 + 0];
|
||||
int g = image[ii * 4 + 1];
|
||||
int b = image[ii * 4 + 2];
|
||||
|
||||
if(r > maxR) maxR = r;
|
||||
if(r < minR) minR = r;
|
||||
if (r > maxR) maxR = r;
|
||||
if (r < minR) minR = r;
|
||||
|
||||
if(g > maxG) maxG = g;
|
||||
if(g < minG) minG = g;
|
||||
if (g > maxG) maxG = g;
|
||||
if (g < minG) minG = g;
|
||||
|
||||
if(b > maxB) maxB = b;
|
||||
if(b < minB) minB = b;
|
||||
}
|
||||
if (b > maxB) maxB = b;
|
||||
if (b < minB) minB = b;
|
||||
}
|
||||
|
||||
int rRange = maxR - minR;
|
||||
int gRange = maxG - minG;
|
||||
int bRange = maxB - minB;
|
||||
int rRange = maxR - minR;
|
||||
int gRange = maxG - minG;
|
||||
int bRange = maxB - minB;
|
||||
|
||||
// and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it)
|
||||
int splitCom = 1;
|
||||
if(bRange > gRange) splitCom = 2;
|
||||
if(rRange > bRange && rRange > gRange) splitCom = 0;
|
||||
// and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it)
|
||||
int splitCom = 1;
|
||||
if (bRange > gRange) splitCom = 2;
|
||||
if (rRange > bRange && rRange > gRange) splitCom = 0;
|
||||
|
||||
int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt);
|
||||
int subPixelsB = numPixels-subPixelsA;
|
||||
int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt);
|
||||
int subPixelsB = numPixels - subPixelsA;
|
||||
|
||||
GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA);
|
||||
GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA);
|
||||
|
||||
pal->treeSplitElt[treeNode] = (uint8_t)splitCom;
|
||||
pal->treeSplit[treeNode] = image[subPixelsA*4+splitCom];
|
||||
pal->treeSplitElt[treeNode] = (uint8_t)splitCom;
|
||||
pal->treeSplit[treeNode] = image[subPixelsA * 4 + splitCom];
|
||||
|
||||
GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, buildForDither, pal);
|
||||
GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2+1, buildForDither, pal);
|
||||
GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt - splitDist, splitDist / 2, treeNode * 2, buildForDither, pal);
|
||||
GifSplitPalette(image + subPixelsA * 4,
|
||||
subPixelsB,
|
||||
splitElt,
|
||||
lastElt,
|
||||
splitElt + splitDist,
|
||||
splitDist / 2,
|
||||
treeNode * 2 + 1,
|
||||
buildForDither,
|
||||
pal);
|
||||
}
|
||||
|
||||
// Finds all pixels that have changed from the previous image and
|
||||
// moves them to the fromt of th buffer.
|
||||
// This allows us to build a palette optimized for the colors of the
|
||||
// changed pixels only.
|
||||
int GifPickChangedPixels( const uint8_t* lastFrame, uint8_t* frame, int numPixels )
|
||||
{
|
||||
int numChanged = 0;
|
||||
uint8_t* writeIter = frame;
|
||||
int GifPickChangedPixels(const uint8_t * lastFrame, uint8_t * frame, int numPixels) {
|
||||
int numChanged = 0;
|
||||
uint8_t * writeIter = frame;
|
||||
|
||||
for (int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
if(lastFrame[0] != frame[0] ||
|
||||
lastFrame[1] != frame[1] ||
|
||||
lastFrame[2] != frame[2])
|
||||
{
|
||||
writeIter[0] = frame[0];
|
||||
writeIter[1] = frame[1];
|
||||
writeIter[2] = frame[2];
|
||||
++numChanged;
|
||||
writeIter += 4;
|
||||
}
|
||||
lastFrame += 4;
|
||||
frame += 4;
|
||||
}
|
||||
for (int ii = 0; ii < numPixels; ++ii) {
|
||||
if (lastFrame[0] != frame[0] || lastFrame[1] != frame[1] || lastFrame[2] != frame[2]) {
|
||||
writeIter[0] = frame[0];
|
||||
writeIter[1] = frame[1];
|
||||
writeIter[2] = frame[2];
|
||||
++numChanged;
|
||||
writeIter += 4;
|
||||
}
|
||||
lastFrame += 4;
|
||||
frame += 4;
|
||||
}
|
||||
|
||||
return numChanged;
|
||||
return numChanged;
|
||||
}
|
||||
|
||||
// Creates a palette by placing all the image pixels in a k-d tree and then averaging the blocks at the bottom.
|
||||
// This is known as the "modified median split" technique
|
||||
void GifMakePalette( const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_t width, uint32_t height, int bitDepth, bool buildForDither, GifPalette* pPal )
|
||||
{
|
||||
pPal->bitDepth = bitDepth;
|
||||
void GifMakePalette(const uint8_t * lastFrame,
|
||||
const uint8_t * nextFrame,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
int bitDepth,
|
||||
bool buildForDither,
|
||||
GifPalette * pPal) {
|
||||
pPal->bitDepth = bitDepth;
|
||||
|
||||
// SplitPalette is destructive (it sorts the pixels by color) so
|
||||
// we must create a copy of the image for it to destroy
|
||||
size_t imageSize = (size_t)(width * height * 4 * sizeof(uint8_t));
|
||||
uint8_t* destroyableImage = (uint8_t*)GIF_TEMP_MALLOC(imageSize);
|
||||
memcpy(destroyableImage, nextFrame, imageSize);
|
||||
// SplitPalette is destructive (it sorts the pixels by color) so
|
||||
// we must create a copy of the image for it to destroy
|
||||
size_t imageSize = (size_t)(width * height * 4 * sizeof(uint8_t));
|
||||
uint8_t * destroyableImage = (uint8_t *)GIF_TEMP_MALLOC(imageSize);
|
||||
memcpy(destroyableImage, nextFrame, imageSize);
|
||||
|
||||
int numPixels = (int)(width * height);
|
||||
if(lastFrame)
|
||||
numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels);
|
||||
int numPixels = (int)(width * height);
|
||||
if (lastFrame) numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels);
|
||||
|
||||
const int lastElt = 1 << bitDepth;
|
||||
const int splitElt = lastElt/2;
|
||||
const int splitDist = splitElt/2;
|
||||
const int lastElt = 1 << bitDepth;
|
||||
const int splitElt = lastElt / 2;
|
||||
const int splitDist = splitElt / 2;
|
||||
|
||||
GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal);
|
||||
GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal);
|
||||
|
||||
GIF_TEMP_FREE(destroyableImage);
|
||||
GIF_TEMP_FREE(destroyableImage);
|
||||
|
||||
// add the bottom node for the transparency index
|
||||
pPal->treeSplit[1 << (bitDepth-1)] = 0;
|
||||
pPal->treeSplitElt[1 << (bitDepth-1)] = 0;
|
||||
// add the bottom node for the transparency index
|
||||
pPal->treeSplit[1 << (bitDepth - 1)] = 0;
|
||||
pPal->treeSplitElt[1 << (bitDepth - 1)] = 0;
|
||||
|
||||
pPal->r[0] = pPal->g[0] = pPal->b[0] = 0;
|
||||
pPal->r[0] = pPal->g[0] = pPal->b[0] = 0;
|
||||
}
|
||||
|
||||
// Implements Floyd-Steinberg dithering, writes palette value to alpha
|
||||
void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal )
|
||||
{
|
||||
int numPixels = (int)(width * height);
|
||||
void GifDitherImage(const uint8_t * lastFrame,
|
||||
const uint8_t * nextFrame,
|
||||
uint8_t * outFrame,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GifPalette * pPal) {
|
||||
int numPixels = (int)(width * height);
|
||||
|
||||
// quantPixels initially holds color*256 for all pixels
|
||||
// The extra 8 bits of precision allow for sub-single-color error values
|
||||
// to be propagated
|
||||
int32_t *quantPixels = (int32_t *)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4);
|
||||
// quantPixels initially holds color*256 for all pixels
|
||||
// The extra 8 bits of precision allow for sub-single-color error values
|
||||
// to be propagated
|
||||
int32_t * quantPixels = (int32_t *)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4);
|
||||
|
||||
for( int ii=0; ii<numPixels*4; ++ii )
|
||||
{
|
||||
uint8_t pix = nextFrame[ii];
|
||||
int32_t pix16 = (int32_t)(pix) * 256;
|
||||
quantPixels[ii] = pix16;
|
||||
}
|
||||
for (int ii = 0; ii < numPixels * 4; ++ii) {
|
||||
uint8_t pix = nextFrame[ii];
|
||||
int32_t pix16 = (int32_t)(pix)*256;
|
||||
quantPixels[ii] = pix16;
|
||||
}
|
||||
|
||||
for( uint32_t yy=0; yy<height; ++yy )
|
||||
{
|
||||
for( uint32_t xx=0; xx<width; ++xx )
|
||||
{
|
||||
int32_t* nextPix = quantPixels + 4*(yy*width+xx);
|
||||
const uint8_t* lastPix = lastFrame? lastFrame + 4*(yy*width+xx) : NULL;
|
||||
for (uint32_t yy = 0; yy < height; ++yy) {
|
||||
for (uint32_t xx = 0; xx < width; ++xx) {
|
||||
int32_t * nextPix = quantPixels + 4 * (yy * width + xx);
|
||||
const uint8_t * lastPix = lastFrame ? lastFrame + 4 * (yy * width + xx) : NULL;
|
||||
|
||||
// Compute the colors we want (rounding to nearest)
|
||||
int32_t rr = (nextPix[0] + 127) / 256;
|
||||
int32_t gg = (nextPix[1] + 127) / 256;
|
||||
int32_t bb = (nextPix[2] + 127) / 256;
|
||||
// Compute the colors we want (rounding to nearest)
|
||||
int32_t rr = (nextPix[0] + 127) / 256;
|
||||
int32_t gg = (nextPix[1] + 127) / 256;
|
||||
int32_t bb = (nextPix[2] + 127) / 256;
|
||||
|
||||
// if it happens that we want the color from last frame, then just write out
|
||||
// a transparent pixel
|
||||
if( lastFrame &&
|
||||
lastPix[0] == rr &&
|
||||
lastPix[1] == gg &&
|
||||
lastPix[2] == bb )
|
||||
{
|
||||
nextPix[0] = rr;
|
||||
nextPix[1] = gg;
|
||||
nextPix[2] = bb;
|
||||
nextPix[3] = kGifTransIndex;
|
||||
continue;
|
||||
}
|
||||
// if it happens that we want the color from last frame, then just write out
|
||||
// a transparent pixel
|
||||
if (lastFrame && lastPix[0] == rr && lastPix[1] == gg && lastPix[2] == bb) {
|
||||
nextPix[0] = rr;
|
||||
nextPix[1] = gg;
|
||||
nextPix[2] = bb;
|
||||
nextPix[3] = kGifTransIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = kGifTransIndex;
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = kGifTransIndex;
|
||||
|
||||
// Search the palete
|
||||
GifGetClosestPaletteColor(pPal, rr, gg, bb, &bestInd, &bestDiff, 1);
|
||||
// Search the palete
|
||||
GifGetClosestPaletteColor(pPal, rr, gg, bb, &bestInd, &bestDiff, 1);
|
||||
|
||||
// Write the result to the temp buffer
|
||||
int32_t r_err = nextPix[0] - (int32_t)(pPal->r[bestInd]) * 256;
|
||||
int32_t g_err = nextPix[1] - (int32_t)(pPal->g[bestInd]) * 256;
|
||||
int32_t b_err = nextPix[2] - (int32_t)(pPal->b[bestInd]) * 256;
|
||||
// Write the result to the temp buffer
|
||||
int32_t r_err = nextPix[0] - (int32_t)(pPal->r[bestInd]) * 256;
|
||||
int32_t g_err = nextPix[1] - (int32_t)(pPal->g[bestInd]) * 256;
|
||||
int32_t b_err = nextPix[2] - (int32_t)(pPal->b[bestInd]) * 256;
|
||||
|
||||
nextPix[0] = pPal->r[bestInd];
|
||||
nextPix[1] = pPal->g[bestInd];
|
||||
nextPix[2] = pPal->b[bestInd];
|
||||
nextPix[3] = bestInd;
|
||||
nextPix[0] = pPal->r[bestInd];
|
||||
nextPix[1] = pPal->g[bestInd];
|
||||
nextPix[2] = pPal->b[bestInd];
|
||||
nextPix[3] = bestInd;
|
||||
|
||||
// Propagate the error to the four adjacent locations
|
||||
// that we haven't touched yet
|
||||
int quantloc_7 = (int)(yy * width + xx + 1);
|
||||
int quantloc_3 = (int)(yy * width + width + xx - 1);
|
||||
int quantloc_5 = (int)(yy * width + width + xx);
|
||||
int quantloc_1 = (int)(yy * width + width + xx + 1);
|
||||
// Propagate the error to the four adjacent locations
|
||||
// that we haven't touched yet
|
||||
int quantloc_7 = (int)(yy * width + xx + 1);
|
||||
int quantloc_3 = (int)(yy * width + width + xx - 1);
|
||||
int quantloc_5 = (int)(yy * width + width + xx);
|
||||
int quantloc_1 = (int)(yy * width + width + xx + 1);
|
||||
|
||||
if(quantloc_7 < numPixels)
|
||||
{
|
||||
int32_t* pix7 = quantPixels+4*quantloc_7;
|
||||
pix7[0] += GifIMax( -pix7[0], r_err * 7 / 16 );
|
||||
pix7[1] += GifIMax( -pix7[1], g_err * 7 / 16 );
|
||||
pix7[2] += GifIMax( -pix7[2], b_err * 7 / 16 );
|
||||
}
|
||||
if (quantloc_7 < numPixels) {
|
||||
int32_t * pix7 = quantPixels + 4 * quantloc_7;
|
||||
pix7[0] += GifIMax(-pix7[0], r_err * 7 / 16);
|
||||
pix7[1] += GifIMax(-pix7[1], g_err * 7 / 16);
|
||||
pix7[2] += GifIMax(-pix7[2], b_err * 7 / 16);
|
||||
}
|
||||
|
||||
if(quantloc_3 < numPixels)
|
||||
{
|
||||
int32_t* pix3 = quantPixels+4*quantloc_3;
|
||||
pix3[0] += GifIMax( -pix3[0], r_err * 3 / 16 );
|
||||
pix3[1] += GifIMax( -pix3[1], g_err * 3 / 16 );
|
||||
pix3[2] += GifIMax( -pix3[2], b_err * 3 / 16 );
|
||||
}
|
||||
if (quantloc_3 < numPixels) {
|
||||
int32_t * pix3 = quantPixels + 4 * quantloc_3;
|
||||
pix3[0] += GifIMax(-pix3[0], r_err * 3 / 16);
|
||||
pix3[1] += GifIMax(-pix3[1], g_err * 3 / 16);
|
||||
pix3[2] += GifIMax(-pix3[2], b_err * 3 / 16);
|
||||
}
|
||||
|
||||
if(quantloc_5 < numPixels)
|
||||
{
|
||||
int32_t* pix5 = quantPixels+4*quantloc_5;
|
||||
pix5[0] += GifIMax( -pix5[0], r_err * 5 / 16 );
|
||||
pix5[1] += GifIMax( -pix5[1], g_err * 5 / 16 );
|
||||
pix5[2] += GifIMax( -pix5[2], b_err * 5 / 16 );
|
||||
}
|
||||
if (quantloc_5 < numPixels) {
|
||||
int32_t * pix5 = quantPixels + 4 * quantloc_5;
|
||||
pix5[0] += GifIMax(-pix5[0], r_err * 5 / 16);
|
||||
pix5[1] += GifIMax(-pix5[1], g_err * 5 / 16);
|
||||
pix5[2] += GifIMax(-pix5[2], b_err * 5 / 16);
|
||||
}
|
||||
|
||||
if(quantloc_1 < numPixels)
|
||||
{
|
||||
int32_t* pix1 = quantPixels+4*quantloc_1;
|
||||
pix1[0] += GifIMax( -pix1[0], r_err / 16 );
|
||||
pix1[1] += GifIMax( -pix1[1], g_err / 16 );
|
||||
pix1[2] += GifIMax( -pix1[2], b_err / 16 );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (quantloc_1 < numPixels) {
|
||||
int32_t * pix1 = quantPixels + 4 * quantloc_1;
|
||||
pix1[0] += GifIMax(-pix1[0], r_err / 16);
|
||||
pix1[1] += GifIMax(-pix1[1], g_err / 16);
|
||||
pix1[2] += GifIMax(-pix1[2], b_err / 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the palettized result to the output buffer
|
||||
for( int ii=0; ii<numPixels*4; ++ii )
|
||||
{
|
||||
outFrame[ii] = (uint8_t)quantPixels[ii];
|
||||
}
|
||||
// Copy the palettized result to the output buffer
|
||||
for (int ii = 0; ii < numPixels * 4; ++ii) {
|
||||
outFrame[ii] = (uint8_t)quantPixels[ii];
|
||||
}
|
||||
|
||||
GIF_TEMP_FREE(quantPixels);
|
||||
GIF_TEMP_FREE(quantPixels);
|
||||
}
|
||||
|
||||
// Picks palette colors for the image using simple thresholding, no dithering
|
||||
void GifThresholdImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal )
|
||||
{
|
||||
uint32_t numPixels = width*height;
|
||||
for( uint32_t ii=0; ii<numPixels; ++ii )
|
||||
{
|
||||
// if a previous color is available, and it matches the current color,
|
||||
// set the pixel to transparent
|
||||
if(lastFrame &&
|
||||
lastFrame[0] == nextFrame[0] &&
|
||||
lastFrame[1] == nextFrame[1] &&
|
||||
lastFrame[2] == nextFrame[2])
|
||||
{
|
||||
outFrame[0] = lastFrame[0];
|
||||
outFrame[1] = lastFrame[1];
|
||||
outFrame[2] = lastFrame[2];
|
||||
outFrame[3] = kGifTransIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// palettize the pixel
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = 1;
|
||||
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], &bestInd, &bestDiff, 1);
|
||||
void GifThresholdImage(const uint8_t * lastFrame,
|
||||
const uint8_t * nextFrame,
|
||||
uint8_t * outFrame,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GifPalette * pPal) {
|
||||
uint32_t numPixels = width * height;
|
||||
for (uint32_t ii = 0; ii < numPixels; ++ii) {
|
||||
// if a previous color is available, and it matches the current color,
|
||||
// set the pixel to transparent
|
||||
if (lastFrame && lastFrame[0] == nextFrame[0] && lastFrame[1] == nextFrame[1] && lastFrame[2] == nextFrame[2]) {
|
||||
outFrame[0] = lastFrame[0];
|
||||
outFrame[1] = lastFrame[1];
|
||||
outFrame[2] = lastFrame[2];
|
||||
outFrame[3] = kGifTransIndex;
|
||||
} else {
|
||||
// palettize the pixel
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = 1;
|
||||
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], &bestInd, &bestDiff, 1);
|
||||
|
||||
// Write the resulting color to the output buffer
|
||||
outFrame[0] = pPal->r[bestInd];
|
||||
outFrame[1] = pPal->g[bestInd];
|
||||
outFrame[2] = pPal->b[bestInd];
|
||||
outFrame[3] = (uint8_t)bestInd;
|
||||
}
|
||||
// Write the resulting color to the output buffer
|
||||
outFrame[0] = pPal->r[bestInd];
|
||||
outFrame[1] = pPal->g[bestInd];
|
||||
outFrame[2] = pPal->b[bestInd];
|
||||
outFrame[3] = (uint8_t)bestInd;
|
||||
}
|
||||
|
||||
if(lastFrame) lastFrame += 4;
|
||||
outFrame += 4;
|
||||
nextFrame += 4;
|
||||
}
|
||||
if (lastFrame) lastFrame += 4;
|
||||
outFrame += 4;
|
||||
nextFrame += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple structure to write out the LZW-compressed portion of the image
|
||||
// one bit at a time
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bitIndex; // how many bits in the partial byte written so far
|
||||
uint8_t byte; // current partial byte
|
||||
typedef struct {
|
||||
uint8_t bitIndex; // how many bits in the partial byte written so far
|
||||
uint8_t byte; // current partial byte
|
||||
|
||||
uint32_t chunkIndex;
|
||||
uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file
|
||||
uint32_t chunkIndex;
|
||||
uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file
|
||||
} GifBitStatus;
|
||||
|
||||
// insert a single bit
|
||||
void GifWriteBit( GifBitStatus* stat, uint32_t bit )
|
||||
{
|
||||
bit = bit & 1;
|
||||
bit = bit << stat->bitIndex;
|
||||
stat->byte |= bit;
|
||||
void GifWriteBit(GifBitStatus * stat, uint32_t bit) {
|
||||
bit = bit & 1;
|
||||
bit = bit << stat->bitIndex;
|
||||
stat->byte |= bit;
|
||||
|
||||
++stat->bitIndex;
|
||||
if( stat->bitIndex > 7 )
|
||||
{
|
||||
// move the newly-finished byte to the chunk buffer
|
||||
stat->chunk[stat->chunkIndex++] = stat->byte;
|
||||
// and start a new byte
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
}
|
||||
++stat->bitIndex;
|
||||
if (stat->bitIndex > 7) {
|
||||
// move the newly-finished byte to the chunk buffer
|
||||
stat->chunk[stat->chunkIndex++] = stat->byte;
|
||||
// and start a new byte
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// write all bytes so far to the file
|
||||
void GifWriteChunk( FILE* f, GifBitStatus* stat )
|
||||
{
|
||||
fputc((int)stat->chunkIndex, f);
|
||||
fwrite(stat->chunk, 1, stat->chunkIndex, f);
|
||||
void GifWriteChunk(FILE * f, GifBitStatus * stat) {
|
||||
fputc((int)stat->chunkIndex, f);
|
||||
fwrite(stat->chunk, 1, stat->chunkIndex, f);
|
||||
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
stat->chunkIndex = 0;
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
stat->chunkIndex = 0;
|
||||
}
|
||||
|
||||
void GifWriteCode( FILE* f, GifBitStatus* stat, uint32_t code, uint32_t length )
|
||||
{
|
||||
for( uint32_t ii=0; ii<length; ++ii )
|
||||
{
|
||||
GifWriteBit(stat, code);
|
||||
code = code >> 1;
|
||||
void GifWriteCode(FILE * f, GifBitStatus * stat, uint32_t code, uint32_t length) {
|
||||
for (uint32_t ii = 0; ii < length; ++ii) {
|
||||
GifWriteBit(stat, code);
|
||||
code = code >> 1;
|
||||
|
||||
if( stat->chunkIndex == 255 )
|
||||
{
|
||||
GifWriteChunk(f, stat);
|
||||
}
|
||||
}
|
||||
if (stat->chunkIndex == 255) {
|
||||
GifWriteChunk(f, stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The LZW dictionary is a 256-ary tree constructed as the file is encoded,
|
||||
// this is one node
|
||||
typedef struct
|
||||
{
|
||||
uint16_t m_next[256];
|
||||
typedef struct {
|
||||
uint16_t m_next[256];
|
||||
} GifLzwNode;
|
||||
|
||||
// write a 256-color (8-bit) image palette to the file
|
||||
void GifWritePalette( const GifPalette* pPal, FILE* f )
|
||||
{
|
||||
fputc(0, f); // first color: transparency
|
||||
fputc(0, f);
|
||||
fputc(0, f);
|
||||
void GifWritePalette(const GifPalette * pPal, FILE * f) {
|
||||
fputc(0, f); // first color: transparency
|
||||
fputc(0, f);
|
||||
fputc(0, f);
|
||||
|
||||
for(int ii=1; ii<(1 << pPal->bitDepth); ++ii)
|
||||
{
|
||||
uint32_t r = pPal->r[ii];
|
||||
uint32_t g = pPal->g[ii];
|
||||
uint32_t b = pPal->b[ii];
|
||||
for (int ii = 1; ii < (1 << pPal->bitDepth); ++ii) {
|
||||
uint32_t r = pPal->r[ii];
|
||||
uint32_t g = pPal->g[ii];
|
||||
uint32_t b = pPal->b[ii];
|
||||
|
||||
fputc((int)r, f);
|
||||
fputc((int)g, f);
|
||||
fputc((int)b, f);
|
||||
}
|
||||
fputc((int)r, f);
|
||||
fputc((int)g, f);
|
||||
fputc((int)b, f);
|
||||
}
|
||||
}
|
||||
|
||||
// write the image header, LZW-compress and write out the image
|
||||
void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uint32_t width, uint32_t height, uint32_t delay, GifPalette* pPal)
|
||||
{
|
||||
// graphics control extension
|
||||
fputc(0x21, f);
|
||||
fputc(0xf9, f);
|
||||
fputc(0x04, f);
|
||||
fputc(0x05, f); // leave prev frame in place, this frame has transparency
|
||||
fputc(delay & 0xff, f);
|
||||
fputc((delay >> 8) & 0xff, f);
|
||||
fputc(kGifTransIndex, f); // transparent color index
|
||||
fputc(0, f);
|
||||
void GifWriteLzwImage(FILE * f,
|
||||
uint8_t * image,
|
||||
uint32_t left,
|
||||
uint32_t top,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t delay,
|
||||
GifPalette * pPal) {
|
||||
// graphics control extension
|
||||
fputc(0x21, f);
|
||||
fputc(0xf9, f);
|
||||
fputc(0x04, f);
|
||||
fputc(0x05, f); // leave prev frame in place, this frame has transparency
|
||||
fputc(delay & 0xff, f);
|
||||
fputc((delay >> 8) & 0xff, f);
|
||||
fputc(kGifTransIndex, f); // transparent color index
|
||||
fputc(0, f);
|
||||
|
||||
fputc(0x2c, f); // image descriptor block
|
||||
fputc(0x2c, f); // image descriptor block
|
||||
|
||||
fputc(left & 0xff, f); // corner of image in canvas space
|
||||
fputc((left >> 8) & 0xff, f);
|
||||
fputc(top & 0xff, f);
|
||||
fputc((top >> 8) & 0xff, f);
|
||||
fputc(left & 0xff, f); // corner of image in canvas space
|
||||
fputc((left >> 8) & 0xff, f);
|
||||
fputc(top & 0xff, f);
|
||||
fputc((top >> 8) & 0xff, f);
|
||||
|
||||
fputc(width & 0xff, f); // width and height of image
|
||||
fputc((width >> 8) & 0xff, f);
|
||||
fputc(height & 0xff, f);
|
||||
fputc((height >> 8) & 0xff, f);
|
||||
fputc(width & 0xff, f); // width and height of image
|
||||
fputc((width >> 8) & 0xff, f);
|
||||
fputc(height & 0xff, f);
|
||||
fputc((height >> 8) & 0xff, f);
|
||||
|
||||
//fputc(0, f); // no local color table, no transparency
|
||||
//fputc(0x80, f); // no local color table, but transparency
|
||||
// fputc(0, f); // no local color table, no transparency
|
||||
// fputc(0x80, f); // no local color table, but transparency
|
||||
|
||||
fputc(0x80 + pPal->bitDepth-1, f); // local color table present, 2 ^ bitDepth entries
|
||||
GifWritePalette(pPal, f);
|
||||
fputc(0x80 + pPal->bitDepth - 1, f); // local color table present, 2 ^ bitDepth entries
|
||||
GifWritePalette(pPal, f);
|
||||
|
||||
const int minCodeSize = pPal->bitDepth;
|
||||
const uint32_t clearCode = 1 << pPal->bitDepth;
|
||||
const int minCodeSize = pPal->bitDepth;
|
||||
const uint32_t clearCode = 1 << pPal->bitDepth;
|
||||
|
||||
fputc(minCodeSize, f); // min code size 8 bits
|
||||
fputc(minCodeSize, f); // min code size 8 bits
|
||||
|
||||
GifLzwNode* codetree = (GifLzwNode*)GIF_TEMP_MALLOC(sizeof(GifLzwNode)*4096);
|
||||
GifLzwNode * codetree = (GifLzwNode *)GIF_TEMP_MALLOC(sizeof(GifLzwNode) * 4096);
|
||||
|
||||
memset(codetree, 0, sizeof(GifLzwNode)*4096);
|
||||
int32_t curCode = -1;
|
||||
uint32_t codeSize = (uint32_t)minCodeSize + 1;
|
||||
uint32_t maxCode = clearCode+1;
|
||||
memset(codetree, 0, sizeof(GifLzwNode) * 4096);
|
||||
int32_t curCode = -1;
|
||||
uint32_t codeSize = (uint32_t)minCodeSize + 1;
|
||||
uint32_t maxCode = clearCode + 1;
|
||||
|
||||
GifBitStatus stat;
|
||||
stat.byte = 0;
|
||||
stat.bitIndex = 0;
|
||||
stat.chunkIndex = 0;
|
||||
GifBitStatus stat;
|
||||
stat.byte = 0;
|
||||
stat.bitIndex = 0;
|
||||
stat.chunkIndex = 0;
|
||||
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // start with a fresh LZW dictionary
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // start with a fresh LZW dictionary
|
||||
|
||||
for(uint32_t yy=0; yy<height; ++yy)
|
||||
{
|
||||
for(uint32_t xx=0; xx<width; ++xx)
|
||||
{
|
||||
#ifdef GIF_FLIP_VERT
|
||||
// bottom-left origin image (such as an OpenGL capture)
|
||||
uint8_t nextValue = image[((height-1-yy)*width+xx)*4+3];
|
||||
#else
|
||||
// top-left origin
|
||||
uint8_t nextValue = image[(yy*width+xx)*4+3];
|
||||
#endif
|
||||
for (uint32_t yy = 0; yy < height; ++yy) {
|
||||
for (uint32_t xx = 0; xx < width; ++xx) {
|
||||
#ifdef GIF_FLIP_VERT
|
||||
// bottom-left origin image (such as an OpenGL capture)
|
||||
uint8_t nextValue = image[((height - 1 - yy) * width + xx) * 4 + 3];
|
||||
#else
|
||||
// top-left origin
|
||||
uint8_t nextValue = image[(yy * width + xx) * 4 + 3];
|
||||
#endif
|
||||
|
||||
// "loser mode" - no compression, every single code is followed immediately by a clear
|
||||
//WriteCode( f, stat, nextValue, codeSize );
|
||||
//WriteCode( f, stat, 256, codeSize );
|
||||
// "loser mode" - no compression, every single code is followed immediately by a clear
|
||||
// WriteCode( f, stat, nextValue, codeSize );
|
||||
// WriteCode( f, stat, 256, codeSize );
|
||||
|
||||
if( curCode < 0 )
|
||||
{
|
||||
// first value in a new run
|
||||
curCode = nextValue;
|
||||
}
|
||||
else if( codetree[curCode].m_next[nextValue] )
|
||||
{
|
||||
// current run already in the dictionary
|
||||
curCode = codetree[curCode].m_next[nextValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
// finish the current run, write a code
|
||||
GifWriteCode(f, &stat, (uint32_t)curCode, codeSize);
|
||||
if (curCode < 0) {
|
||||
// first value in a new run
|
||||
curCode = nextValue;
|
||||
} else if (codetree[curCode].m_next[nextValue]) {
|
||||
// current run already in the dictionary
|
||||
curCode = codetree[curCode].m_next[nextValue];
|
||||
} else {
|
||||
// finish the current run, write a code
|
||||
GifWriteCode(f, &stat, (uint32_t)curCode, codeSize);
|
||||
|
||||
// insert the new run into the dictionary
|
||||
codetree[curCode].m_next[nextValue] = (uint16_t)++maxCode;
|
||||
// insert the new run into the dictionary
|
||||
codetree[curCode].m_next[nextValue] = (uint16_t)++maxCode;
|
||||
|
||||
if( maxCode >= (1ul << codeSize) )
|
||||
{
|
||||
// dictionary entry count has broken a size barrier,
|
||||
// we need more bits for codes
|
||||
codeSize++;
|
||||
}
|
||||
if( maxCode == 4095 )
|
||||
{
|
||||
// the dictionary is full, clear it out and begin anew
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // clear tree
|
||||
if (maxCode >= (1ul << codeSize)) {
|
||||
// dictionary entry count has broken a size barrier,
|
||||
// we need more bits for codes
|
||||
codeSize++;
|
||||
}
|
||||
if (maxCode == 4095) {
|
||||
// the dictionary is full, clear it out and begin anew
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // clear tree
|
||||
|
||||
memset(codetree, 0, sizeof(GifLzwNode)*4096);
|
||||
codeSize = (uint32_t)(minCodeSize + 1);
|
||||
maxCode = clearCode+1;
|
||||
}
|
||||
memset(codetree, 0, sizeof(GifLzwNode) * 4096);
|
||||
codeSize = (uint32_t)(minCodeSize + 1);
|
||||
maxCode = clearCode + 1;
|
||||
}
|
||||
|
||||
curCode = nextValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
curCode = nextValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compression footer
|
||||
GifWriteCode(f, &stat, (uint32_t)curCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode + 1, (uint32_t)minCodeSize + 1);
|
||||
// compression footer
|
||||
GifWriteCode(f, &stat, (uint32_t)curCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode + 1, (uint32_t)minCodeSize + 1);
|
||||
|
||||
// write out the last partial chunk
|
||||
while( stat.bitIndex ) GifWriteBit(&stat, 0);
|
||||
if( stat.chunkIndex ) GifWriteChunk(f, &stat);
|
||||
// write out the last partial chunk
|
||||
while (stat.bitIndex)
|
||||
GifWriteBit(&stat, 0);
|
||||
if (stat.chunkIndex) GifWriteChunk(f, &stat);
|
||||
|
||||
fputc(0, f); // image block terminator
|
||||
fputc(0, f); // image block terminator
|
||||
|
||||
GIF_TEMP_FREE(codetree);
|
||||
GIF_TEMP_FREE(codetree);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FILE* f;
|
||||
uint8_t* oldImage;
|
||||
bool firstFrame;
|
||||
typedef struct {
|
||||
FILE * f;
|
||||
uint8_t * oldImage;
|
||||
bool firstFrame;
|
||||
} GifWriter;
|
||||
|
||||
// Creates a gif file.
|
||||
// The input GIFWriter is assumed to be uninitialized.
|
||||
// The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value.
|
||||
bool GifBegin( GifWriter* writer, const char* filename, uint32_t width, uint32_t height, uint32_t delay, int32_t bitDepth = 8, bool dither = false )
|
||||
{
|
||||
(void)bitDepth; (void)dither; // Mute "Unused argument" warnings
|
||||
bool GifBegin(GifWriter * writer,
|
||||
const char * filename,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t delay,
|
||||
int32_t bitDepth = 8,
|
||||
bool dither = false) {
|
||||
(void)bitDepth;
|
||||
(void)dither; // Mute "Unused argument" warnings
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
writer->f = 0;
|
||||
fopen_s(&writer->f, filename, "wb");
|
||||
fopen_s(&writer->f, filename, "wb");
|
||||
#else
|
||||
writer->f = fopen(filename, "wb");
|
||||
writer->f = fopen(filename, "wb");
|
||||
#endif
|
||||
if(!writer->f) return false;
|
||||
if (!writer->f) return false;
|
||||
|
||||
writer->firstFrame = true;
|
||||
writer->firstFrame = true;
|
||||
|
||||
// allocate
|
||||
writer->oldImage = (uint8_t*)GIF_MALLOC(width*height*4);
|
||||
// allocate
|
||||
writer->oldImage = (uint8_t *)GIF_MALLOC(width * height * 4);
|
||||
|
||||
fputs("GIF89a", writer->f);
|
||||
fputs("GIF89a", writer->f);
|
||||
|
||||
// screen descriptor
|
||||
fputc(width & 0xff, writer->f);
|
||||
fputc((width >> 8) & 0xff, writer->f);
|
||||
fputc(height & 0xff, writer->f);
|
||||
fputc((height >> 8) & 0xff, writer->f);
|
||||
// screen descriptor
|
||||
fputc(width & 0xff, writer->f);
|
||||
fputc((width >> 8) & 0xff, writer->f);
|
||||
fputc(height & 0xff, writer->f);
|
||||
fputc((height >> 8) & 0xff, writer->f);
|
||||
|
||||
fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entries
|
||||
fputc(0, writer->f); // background color
|
||||
fputc(0, writer->f); // pixels are square (we need to specify this because it's 1989)
|
||||
fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entries
|
||||
fputc(0, writer->f); // background color
|
||||
fputc(0, writer->f); // pixels are square (we need to specify this because it's 1989)
|
||||
|
||||
// now the "global" palette (really just a dummy palette)
|
||||
// color 0: black
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
// color 1: also black
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
// now the "global" palette (really just a dummy palette)
|
||||
// color 0: black
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
// color 1: also black
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
|
||||
if( delay != 0 )
|
||||
{
|
||||
// animation header
|
||||
fputc(0x21, writer->f); // extension
|
||||
fputc(0xff, writer->f); // application specific
|
||||
fputc(11, writer->f); // length 11
|
||||
fputs("NETSCAPE2.0", writer->f); // yes, really
|
||||
fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data
|
||||
if (delay != 0) {
|
||||
// animation header
|
||||
fputc(0x21, writer->f); // extension
|
||||
fputc(0xff, writer->f); // application specific
|
||||
fputc(11, writer->f); // length 11
|
||||
fputs("NETSCAPE2.0", writer->f); // yes, really
|
||||
fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data
|
||||
|
||||
fputc(1, writer->f); // JUST BECAUSE
|
||||
fputc(0, writer->f); // loop infinitely (byte 0)
|
||||
fputc(0, writer->f); // loop infinitely (byte 1)
|
||||
fputc(1, writer->f); // JUST BECAUSE
|
||||
fputc(0, writer->f); // loop infinitely (byte 0)
|
||||
fputc(0, writer->f); // loop infinitely (byte 1)
|
||||
|
||||
fputc(0, writer->f); // block terminator
|
||||
}
|
||||
fputc(0, writer->f); // block terminator
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes out a new frame to a GIF in progress.
|
||||
// The GIFWriter should have been created by GIFBegin.
|
||||
// AFAIK, it is legal to use different bit depths for different frames of an image -
|
||||
// this may be handy to save bits in animations that don't change much.
|
||||
bool GifWriteFrame( GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, int bitDepth = 8, bool dither = false )
|
||||
{
|
||||
if(!writer->f) return false;
|
||||
bool GifWriteFrame(GifWriter * writer,
|
||||
const uint8_t * image,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t delay,
|
||||
int bitDepth = 8,
|
||||
bool dither = false) {
|
||||
if (!writer->f) return false;
|
||||
|
||||
const uint8_t* oldImage = writer->firstFrame? NULL : writer->oldImage;
|
||||
writer->firstFrame = false;
|
||||
const uint8_t * oldImage = writer->firstFrame ? NULL : writer->oldImage;
|
||||
writer->firstFrame = false;
|
||||
|
||||
GifPalette pal;
|
||||
GifMakePalette((dither? NULL : oldImage), image, width, height, bitDepth, dither, &pal);
|
||||
GifPalette pal;
|
||||
GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal);
|
||||
|
||||
if(dither)
|
||||
GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal);
|
||||
else
|
||||
GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal);
|
||||
if (dither)
|
||||
GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal);
|
||||
else
|
||||
GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal);
|
||||
|
||||
GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal);
|
||||
GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes the EOF code, closes the file handle, and frees temp memory used by a GIF.
|
||||
// Many if not most viewers will still display a GIF properly if the EOF code is missing,
|
||||
// but it's still a good idea to write it out.
|
||||
bool GifEnd( GifWriter* writer )
|
||||
{
|
||||
if(!writer->f) return false;
|
||||
bool GifEnd(GifWriter * writer) {
|
||||
if (!writer->f) return false;
|
||||
|
||||
fputc(0x3b, writer->f); // end of file
|
||||
fclose(writer->f);
|
||||
GIF_FREE(writer->oldImage);
|
||||
fputc(0x3b, writer->f); // end of file
|
||||
fclose(writer->f);
|
||||
GIF_FREE(writer->oldImage);
|
||||
|
||||
writer->f = NULL;
|
||||
writer->oldImage = NULL;
|
||||
writer->f = NULL;
|
||||
writer->oldImage = NULL;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+532
-457
@@ -1,19 +1,21 @@
|
||||
#include "graphic.h"
|
||||
|
||||
#include "gif.h"
|
||||
#include "qad_types.h"
|
||||
#include "uglwidget.h"
|
||||
#include "ui_graphic.h"
|
||||
#include "ui_graphic_conf.h"
|
||||
#include <float.h>
|
||||
#include <QMetaObject>
|
||||
|
||||
#include <QActionGroup>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QTapAndHoldGesture>
|
||||
#include <QMetaObject>
|
||||
#include <QPanGesture>
|
||||
#include <QPinchGesture>
|
||||
#include <QActionGroup>
|
||||
#include <QScrollArea>
|
||||
#include <QTapAndHoldGesture>
|
||||
#include <QTimer>
|
||||
#include <QInputDialog>
|
||||
#include "gif.h"
|
||||
#include <float.h>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
# include <QRandomGenerator>
|
||||
#endif
|
||||
@@ -21,12 +23,12 @@
|
||||
# define NO_BUTTONS
|
||||
#else
|
||||
# ifndef FORCE_NO_GL
|
||||
# define HAS_GL
|
||||
# define HAS_GL
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAS_GL
|
||||
# ifndef GL_MULTISAMPLE
|
||||
# define GL_MULTISAMPLE 0x809D
|
||||
# define GL_MULTISAMPLE 0x809D
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -42,7 +44,7 @@ enum DateComponent {
|
||||
};
|
||||
|
||||
const char _button_prop_name_[] = "_button_";
|
||||
const double rad2deg_qpie = 45. / atan(1.);
|
||||
const double rad2deg_qpie = 45. / atan(1.);
|
||||
|
||||
__GraphicRegistrator__ __graphic_registrator__;
|
||||
|
||||
@@ -61,6 +63,7 @@ public:
|
||||
w->setAutoFillBackground(false);
|
||||
}
|
||||
int minimum_hei;
|
||||
|
||||
protected:
|
||||
virtual QSize sizeHint() const {
|
||||
QSize ret;
|
||||
@@ -68,26 +71,24 @@ protected:
|
||||
ret = widget()->sizeHint();
|
||||
return ret;
|
||||
}
|
||||
virtual QSize minimumSizeHint() const {
|
||||
return QSize(1, minimum_hei);
|
||||
}
|
||||
virtual QSize minimumSizeHint() const { return QSize(1, minimum_hei); }
|
||||
};
|
||||
|
||||
|
||||
Graphic::Graphic(QWidget * parent): QFrame(parent), canvas(0), line_x_min(this), line_x_max(this), line_y_min(this), line_y_max(this) {
|
||||
canvas_gl = 0;
|
||||
canvas_gl = 0;
|
||||
timer_pause = timer_record = 0;
|
||||
gesture_angle = 45.;
|
||||
leg_update = true;
|
||||
gesture_angle = 45.;
|
||||
leg_update = true;
|
||||
visible_update = fullscr = need_mouse_pan = m_fakeGL = false;
|
||||
gestures =
|
||||
#ifdef Q_OS_ANDROID
|
||||
true;
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
false;
|
||||
#endif
|
||||
func_gridMarkX = func_gridMarkY = nullptr;
|
||||
ui = new Ui::Graphic();
|
||||
ui = new Ui::Graphic();
|
||||
ui->setupUi(this);
|
||||
ui->scrollLegend->layout()->addWidget(new LegendScrollArea(ui->widgetLegend));
|
||||
ui->scrollLegend->hide();
|
||||
@@ -95,21 +96,20 @@ Graphic::Graphic(QWidget * parent): QFrame(parent), canvas(0), line_x_min(this),
|
||||
#ifdef NO_BUTTONS
|
||||
ui->widgetLeft->hide();
|
||||
ui->widgetRight->hide();
|
||||
QList<QToolButton*> btnlist = {
|
||||
ui->graphic_buttonAutofit,
|
||||
ui->graphic_checkGrid,
|
||||
ui->graphic_checkGuides,
|
||||
ui->graphic_buttonFullscreen,
|
||||
ui->graphic_checkBorderInputs,
|
||||
ui->graphic_checkLegend,
|
||||
ui->graphic_checkPause,
|
||||
ui->graphic_buttonConfigure,
|
||||
ui->graphic_buttonSave,
|
||||
ui->graphic_buttonExport,
|
||||
ui->graphic_buttonRecord,
|
||||
ui->graphic_buttonClear,
|
||||
ui->graphic_buttonClose};
|
||||
buttons_menu = new QMenu(this);
|
||||
QList<QToolButton *> btnlist = {ui->graphic_buttonAutofit,
|
||||
ui->graphic_checkGrid,
|
||||
ui->graphic_checkGuides,
|
||||
ui->graphic_buttonFullscreen,
|
||||
ui->graphic_checkBorderInputs,
|
||||
ui->graphic_checkLegend,
|
||||
ui->graphic_checkPause,
|
||||
ui->graphic_buttonConfigure,
|
||||
ui->graphic_buttonSave,
|
||||
ui->graphic_buttonExport,
|
||||
ui->graphic_buttonRecord,
|
||||
ui->graphic_buttonClear,
|
||||
ui->graphic_buttonClose};
|
||||
buttons_menu = new QMenu(this);
|
||||
for (auto * b: btnlist) {
|
||||
auto * a = new QAction(this);
|
||||
connect(a, SIGNAL(triggered()), b, SLOT(click()));
|
||||
@@ -120,31 +120,31 @@ Graphic::Graphic(QWidget * parent): QFrame(parent), canvas(0), line_x_min(this),
|
||||
}
|
||||
#endif
|
||||
QActionGroup * agroup = new QActionGroup(this);
|
||||
agroup->addAction(ui->graphic_actionGuidesFree );
|
||||
agroup->addAction(ui->graphic_actionGuidesTrace );
|
||||
agroup->addAction(ui->graphic_actionGuidesFree);
|
||||
agroup->addAction(ui->graphic_actionGuidesTrace);
|
||||
agroup->addAction(ui->graphic_actionGuidesTraceX);
|
||||
agroup->addAction(ui->graphic_actionGuidesTraceY);
|
||||
ui->graphic_actionGuidesFree ->setProperty("_value", (int)Free );
|
||||
ui->graphic_actionGuidesTrace ->setProperty("_value", (int)TraceXY);
|
||||
ui->graphic_actionGuidesTraceX->setProperty("_value", (int)TraceX );
|
||||
ui->graphic_actionGuidesTraceY->setProperty("_value", (int)TraceY );
|
||||
ui->graphic_actionGuidesFree->setProperty("_value", (int)Free);
|
||||
ui->graphic_actionGuidesTrace->setProperty("_value", (int)TraceXY);
|
||||
ui->graphic_actionGuidesTraceX->setProperty("_value", (int)TraceX);
|
||||
ui->graphic_actionGuidesTraceY->setProperty("_value", (int)TraceY);
|
||||
ui->graphic_actionGuidesFree->setChecked(true);
|
||||
connect(agroup, SIGNAL(triggered(QAction*)), this, SLOT(actionGuidesTriggered(QAction*)));
|
||||
ui->graphic_checkGuides ->addAction(ui->graphic_actionGuidesFree );
|
||||
ui->graphic_checkGuides ->addAction(ui->graphic_actionGuidesTrace );
|
||||
ui->graphic_checkGuides ->addAction(ui->graphic_actionGuidesTraceX);
|
||||
ui->graphic_checkGuides ->addAction(ui->graphic_actionGuidesTraceY);
|
||||
connect(agroup, SIGNAL(triggered(QAction *)), this, SLOT(actionGuidesTriggered(QAction *)));
|
||||
ui->graphic_checkGuides->addAction(ui->graphic_actionGuidesFree);
|
||||
ui->graphic_checkGuides->addAction(ui->graphic_actionGuidesTrace);
|
||||
ui->graphic_checkGuides->addAction(ui->graphic_actionGuidesTraceX);
|
||||
ui->graphic_checkGuides->addAction(ui->graphic_actionGuidesTraceY);
|
||||
ui->graphic_buttonAutofit->addAction(ui->graphic_actionExpandX);
|
||||
ui->graphic_buttonAutofit->addAction(ui->graphic_actionExpandY);
|
||||
line_x_min.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
line_x_max.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
((QBoxLayout * )ui->widgetLY->layout())->insertWidget(0, &line_y_min);
|
||||
((QBoxLayout * )ui->widgetLY->layout())->addWidget(&line_y_max);
|
||||
((QBoxLayout * )ui->widgetLX->layout())->insertWidget(0, &line_x_min);
|
||||
((QBoxLayout * )ui->widgetLX->layout())->addWidget(&line_x_max);
|
||||
((QBoxLayout *)ui->widgetLY->layout())->insertWidget(0, &line_y_min);
|
||||
((QBoxLayout *)ui->widgetLY->layout())->addWidget(&line_y_max);
|
||||
((QBoxLayout *)ui->widgetLX->layout())->insertWidget(0, &line_x_min);
|
||||
((QBoxLayout *)ui->widgetLX->layout())->addWidget(&line_x_max);
|
||||
tm.restart();
|
||||
grid_numbers_x = grid_numbers_y = 1;
|
||||
LN10 = qLn(10.);
|
||||
LN10 = qLn(10.);
|
||||
line_x_min.setClearButtonVisible(true);
|
||||
line_x_max.setClearButtonVisible(true);
|
||||
line_y_min.setClearButtonVisible(true);
|
||||
@@ -153,12 +153,12 @@ Graphic::Graphic(QWidget * parent): QFrame(parent), canvas(0), line_x_min(this),
|
||||
connect(&line_x_max, SIGNAL(valueChanged(double)), this, SLOT(lineXMaxChanged(double)));
|
||||
connect(&line_y_min, SIGNAL(valueChanged(double)), this, SLOT(lineYMinChanged(double)));
|
||||
connect(&line_y_max, SIGNAL(valueChanged(double)), this, SLOT(lineYMaxChanged(double)));
|
||||
connect(ui->canvas_raster, SIGNAL(paintEvent(QPaintEvent * )), this, SLOT(canvasPaintEvent()));
|
||||
connect(ui->canvas_raster, SIGNAL(paintEvent(QPaintEvent *)), this, SLOT(canvasPaintEvent()));
|
||||
prepareCanvas(ui->canvas_raster);
|
||||
icon_exp_x = QIcon(":/icons/expand_x.png");
|
||||
icon_exp_y = QIcon(":/icons/expand_y.png");
|
||||
icon_exp_sx = QIcon(":/icons/expand_s_x.png");
|
||||
icon_exp_sy = QIcon(":/icons/expand_s_y.png");
|
||||
icon_exp_x = QIcon(":/icons/expand_x.png");
|
||||
icon_exp_y = QIcon(":/icons/expand_y.png");
|
||||
icon_exp_sx = QIcon(":/icons/expand_s_x.png");
|
||||
icon_exp_sy = QIcon(":/icons/expand_s_y.png");
|
||||
icon_pause_b = QImage(":/icons/pause-back.png");
|
||||
icon_pause_f = QImage(":/icons/pause-front.png");
|
||||
aupdate = grid = isFit = navigation = true;
|
||||
@@ -167,17 +167,17 @@ Graphic::Graphic(QWidget * parent): QFrame(parent), canvas(0), line_x_min(this),
|
||||
limit_.setCoords(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
eminx = eminy = DBL_MAX;
|
||||
emaxx = emaxy = DBL_MIN;
|
||||
grad_x = grad_y = Auto;
|
||||
axis_type_x = Numeric;
|
||||
grad_x = grad_y = Auto;
|
||||
axis_type_x = Numeric;
|
||||
floating_axis_type = Free;
|
||||
min_repaint_int = 25;
|
||||
min_repaint_int = 25;
|
||||
lastw = lasth = 0;
|
||||
inc_x = 1.;
|
||||
//buffer = 0;
|
||||
inc_x = 1.;
|
||||
// buffer = 0;
|
||||
gridx = gridy = 1.;
|
||||
history = 5.;
|
||||
visible_time = -1.;
|
||||
thick = lineThickness(this);
|
||||
history = 5.;
|
||||
visible_time = -1.;
|
||||
thick = lineThickness(this);
|
||||
#if QT_VERSION_MAJOR >= 5
|
||||
thick *= devicePixelRatio();
|
||||
#endif
|
||||
@@ -189,13 +189,13 @@ Graphic::Graphic(QWidget * parent): QFrame(parent), canvas(0), line_x_min(this),
|
||||
selbrush.setStyle(Qt::SolidPattern);
|
||||
selbrush.setColor(QColor(60, 175, 255, 100));
|
||||
text_color = palette().color(QPalette::WindowText);
|
||||
grid_pen = QPen(palette().color(QPalette::Disabled, QPalette::WindowText), 0., Qt::DotLine);
|
||||
grid_pen = QPen(palette().color(QPalette::Disabled, QPalette::WindowText), 0., Qt::DotLine);
|
||||
graphics.append(GraphicType());
|
||||
curGraphic = curTrace = 0;
|
||||
selpen = palette().color(QPalette::WindowText);
|
||||
selpen = palette().color(QPalette::WindowText);
|
||||
selpen.setStyle(Qt::DashLine);
|
||||
back_color = palette().color(QPalette::Base);
|
||||
buttons_ = AllButtons;
|
||||
buttons_ = AllButtons;
|
||||
setOpenGL(false);
|
||||
setButtonsPosition(Graphic::Left);
|
||||
setAntialiasing(false);
|
||||
@@ -215,7 +215,7 @@ Graphic::~Graphic() {
|
||||
delete buttons_menu;
|
||||
#endif
|
||||
delete conf;
|
||||
//if (buffer != 0) delete buffer;
|
||||
// if (buffer != 0) delete buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ void Graphic::changeEvent(QEvent * e) {
|
||||
void Graphic::resizeEvent(QResizeEvent *) {
|
||||
if (leg_update)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
QTimer::singleShot(0, this, [this](){updateLegend(false);});
|
||||
QTimer::singleShot(0, this, [this]() { updateLegend(false); });
|
||||
#else
|
||||
updateLegend(false);
|
||||
#endif
|
||||
@@ -241,7 +241,7 @@ void Graphic::resizeEvent(QResizeEvent *) {
|
||||
|
||||
void Graphic::showEvent(QShowEvent *) {
|
||||
if (need_createGL && !canvas_gl) {
|
||||
//qDebug() << "create GL on show";
|
||||
// qDebug() << "create GL on show";
|
||||
canvas_gl = new UGLWidget();
|
||||
ui->layoutCanvas->addWidget(canvas_gl);
|
||||
connect(canvas_gl, SIGNAL(paintSignal()), this, SLOT(canvasPaintEvent()));
|
||||
@@ -257,8 +257,7 @@ void Graphic::showEvent(QShowEvent *) {
|
||||
void Graphic::timerEvent(QTimerEvent * e) {
|
||||
if (e->timerId() == timer_pause) {
|
||||
pause_phase += 0.02;
|
||||
if (pause_phase > 1.)
|
||||
pause_phase -= 1.;
|
||||
if (pause_phase > 1.) pause_phase -= 1.;
|
||||
update();
|
||||
}
|
||||
if (e->timerId() == timer_record) {
|
||||
@@ -274,16 +273,16 @@ bool Graphic::eventFilter(QObject * o, QEvent * e) {
|
||||
switch (e->type()) {
|
||||
case QEvent::Gesture:
|
||||
if (!navigation || !gestures) break;
|
||||
foreach (QGesture * g, ((QGestureEvent*)e)->gestures())
|
||||
foreach(QGesture * g, ((QGestureEvent *)e)->gestures())
|
||||
procGesture(g);
|
||||
break;
|
||||
case QEvent::KeyPress: {
|
||||
int k = ((QKeyEvent*)e)->key();
|
||||
int k = ((QKeyEvent *)e)->key();
|
||||
if ((k == Qt::Key_Back || k == Qt::Key_Escape) && fullscr) {
|
||||
leaveFullscreen();
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
} break;
|
||||
case QEvent::TouchBegin:
|
||||
if (!navigation || !gestures) break;
|
||||
need_mouse_pan = true;
|
||||
@@ -292,9 +291,9 @@ bool Graphic::eventFilter(QObject * o, QEvent * e) {
|
||||
if (!navigation || !gestures) break;
|
||||
QList<QTouchEvent::TouchPoint> tpl =
|
||||
#if QT_VERSION_MAJOR <= 5
|
||||
((QTouchEvent*)e)->touchPoints();
|
||||
((QTouchEvent *)e)->touchPoints();
|
||||
#else
|
||||
((QTouchEvent*)e)->points();
|
||||
((QTouchEvent *)e)->points();
|
||||
#endif
|
||||
if (tpl.size() == 2) {
|
||||
need_mouse_pan = false;
|
||||
@@ -306,7 +305,7 @@ bool Graphic::eventFilter(QObject * o, QEvent * e) {
|
||||
#endif
|
||||
gesture_angle = rad2deg_qpie * qAtan2(qAbs(dp.y()), qAbs(dp.x()));
|
||||
}
|
||||
} break;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -315,13 +314,13 @@ bool Graphic::eventFilter(QObject * o, QEvent * e) {
|
||||
|
||||
|
||||
void Graphic::prepareCanvas(QWidget * w) {
|
||||
connect(w, SIGNAL(mouseMoveEvent(QMouseEvent * )), this, SLOT(canvasMouseMoveEvent(QMouseEvent * )));
|
||||
connect(w, SIGNAL(mousePressEvent(QMouseEvent * )), this, SLOT(canvasMousePressEvent(QMouseEvent * )));
|
||||
connect(w, SIGNAL(mouseReleaseEvent(QMouseEvent * )), this, SLOT(canvasMouseReleaseEvent(QMouseEvent * )));
|
||||
connect(w, SIGNAL(mouseDoubleClickEvent(QMouseEvent*)), this, SLOT(canvasMouseDoubleClickEvent(QMouseEvent * )));
|
||||
connect(w, SIGNAL(wheelEvent(QWheelEvent * )), this, SLOT(canvasWheelEvent(QWheelEvent * )));
|
||||
connect(w, SIGNAL(leaveEvent(QEvent * )), this, SLOT(canvasLeaveEvent(QEvent * )));
|
||||
connect(w, SIGNAL(keyPressEvent(QKeyEvent * )), this, SLOT(canvasKeyPressEvent(QKeyEvent * )));
|
||||
connect(w, SIGNAL(mouseMoveEvent(QMouseEvent *)), this, SLOT(canvasMouseMoveEvent(QMouseEvent *)));
|
||||
connect(w, SIGNAL(mousePressEvent(QMouseEvent *)), this, SLOT(canvasMousePressEvent(QMouseEvent *)));
|
||||
connect(w, SIGNAL(mouseReleaseEvent(QMouseEvent *)), this, SLOT(canvasMouseReleaseEvent(QMouseEvent *)));
|
||||
connect(w, SIGNAL(mouseDoubleClickEvent(QMouseEvent *)), this, SLOT(canvasMouseDoubleClickEvent(QMouseEvent *)));
|
||||
connect(w, SIGNAL(wheelEvent(QWheelEvent *)), this, SLOT(canvasWheelEvent(QWheelEvent *)));
|
||||
connect(w, SIGNAL(leaveEvent(QEvent *)), this, SLOT(canvasLeaveEvent(QEvent *)));
|
||||
connect(w, SIGNAL(keyPressEvent(QKeyEvent *)), this, SLOT(canvasKeyPressEvent(QKeyEvent *)));
|
||||
w->grabGesture(Qt::TapAndHoldGesture);
|
||||
w->grabGesture(Qt::PanGesture);
|
||||
w->grabGesture(Qt::PinchGesture);
|
||||
@@ -335,15 +334,15 @@ void Graphic::procGesture(QGesture * g) {
|
||||
switch (g->gestureType()) {
|
||||
case Qt::PanGesture: {
|
||||
if (need_mouse_pan) break;
|
||||
QPanGesture * pg = (QPanGesture*)g;
|
||||
QPointF dp = -pg->delta();
|
||||
QPanGesture * pg = (QPanGesture *)g;
|
||||
QPointF dp = -pg->delta();
|
||||
dp.rx() /= getScaleX();
|
||||
dp.ry() /= getScaleY();
|
||||
selrect.translate(dp);
|
||||
totalUpdate();
|
||||
} break;
|
||||
} break;
|
||||
case Qt::PinchGesture: {
|
||||
QPinchGesture * pg = (QPinchGesture*)g;
|
||||
QPinchGesture * pg = (QPinchGesture *)g;
|
||||
Qt::KeyboardModifiers km = Qt::NoModifier;
|
||||
if (gesture_angle <= 20.) km = Qt::ControlModifier;
|
||||
if (gesture_angle >= 70.) km = Qt::ShiftModifier;
|
||||
@@ -351,33 +350,33 @@ void Graphic::procGesture(QGesture * g) {
|
||||
if (!fullscr) cp = mapFromGlobal(cp);
|
||||
procZoom(cp, (pg->scaleFactor() - 1.) * 500., km);
|
||||
totalUpdate();
|
||||
} break;
|
||||
} break;
|
||||
case Qt::TapAndHoldGesture: {
|
||||
QTapAndHoldGesture * pg = (QTapAndHoldGesture*)g;
|
||||
QTapAndHoldGesture * pg = (QTapAndHoldGesture *)g;
|
||||
if (pg->state() == Qt::GestureStarted)
|
||||
QMetaObject::invokeMethod(this, [this](){showMenu();}, Qt::QueuedConnection);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this]() { showMenu(); },
|
||||
Qt::QueuedConnection);
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Graphic::procZoom(QPointF view_center, double dzoom, Qt::KeyboardModifiers km) {
|
||||
double scl, wid = canvas->width() - gridborder.x() - margins_.width() - margins_.left(), hei = canvas->height() - gridborder.y() - margins_.height() - margins_.top();
|
||||
double scl, wid = canvas->width() - gridborder.x() - margins_.width() - margins_.left(),
|
||||
hei = canvas->height() - gridborder.y() - margins_.height() - margins_.top();
|
||||
double px = view_center.x() - gridborder.x() - margins_.left(), py = hei - view_center.y() + margins_.height();
|
||||
px = px / wid * selrect.width() + selrect.x();
|
||||
py = py / hei * selrect.height() + selrect.y();
|
||||
px = px / wid * selrect.width() + selrect.x();
|
||||
py = py / hei * selrect.height() + selrect.y();
|
||||
scl = 1. - dzoom / 500.;
|
||||
if (km == Qt::NoModifier)
|
||||
selrect.setRect(px - (px - selrect.x()) * scl, py - (py - selrect.y()) * scl, selrect.width() * scl, selrect.height() * scl);
|
||||
else {
|
||||
if (km == Qt::ControlModifier)
|
||||
selrect.setRect(px - (px - selrect.x()) * scl, selrect.y(), selrect.width() * scl, selrect.height());
|
||||
if (km == Qt::ShiftModifier)
|
||||
selrect.setRect(selrect.x(), py - (py - selrect.y()) * scl, selrect.width(), selrect.height() * scl);
|
||||
if (km == Qt::AltModifier)
|
||||
selrect.translate((dzoom > 0. ? 1. : -1.) * selrect.width() / 2., 0.);
|
||||
if (km == Qt::ControlModifier) selrect.setRect(px - (px - selrect.x()) * scl, selrect.y(), selrect.width() * scl, selrect.height());
|
||||
if (km == Qt::ShiftModifier) selrect.setRect(selrect.x(), py - (py - selrect.y()) * scl, selrect.width(), selrect.height() * scl);
|
||||
if (km == Qt::AltModifier) selrect.translate((dzoom > 0. ? 1. : -1.) * selrect.width() / 2., 0.);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,23 +391,22 @@ void Graphic::totalUpdate() {
|
||||
|
||||
void Graphic::canvasPaintEvent() {
|
||||
if (is_lines_update) return;
|
||||
int wid = canvas->width (),hei = canvas->height();
|
||||
int wid = canvas->width(), hei = canvas->height();
|
||||
if (canvas->isHidden() || wid <= 1 || hei <= 1) return;
|
||||
if (!buffer.isNull()) {
|
||||
if (lastw != wid || lasth != hei)
|
||||
buffer = QPixmap();
|
||||
if (lastw != wid || lasth != hei) buffer = QPixmap();
|
||||
}
|
||||
if (buffer.isNull()) {
|
||||
#if QT_VERSION_MAJOR >= 5
|
||||
const qreal dpr = canvas->devicePixelRatio();
|
||||
buffer = QPixmap(canvas->size() * dpr);
|
||||
buffer = QPixmap(canvas->size() * dpr);
|
||||
buffer.setDevicePixelRatio(dpr);
|
||||
#else
|
||||
buffer = QPixmap(canvas->size());
|
||||
#endif
|
||||
}
|
||||
lastw = wid;
|
||||
lasth = hei;
|
||||
lastw = wid;
|
||||
lasth = hei;
|
||||
font_sz = fontMetrics().size(0, "0");
|
||||
font_sz.setHeight(font_sz.height() * 1.);
|
||||
#ifdef Q_OS_ANDROID
|
||||
@@ -452,13 +450,14 @@ void Graphic::canvasPaintEvent() {
|
||||
painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y()));
|
||||
emit beforeGraphicPaintEvent(painter);
|
||||
painter->setClipping(false);
|
||||
if (grid)
|
||||
drawGrid();
|
||||
if (grid) drawGrid();
|
||||
p.setRenderHint(QPainter::Antialiasing, aalias);
|
||||
#ifdef HAS_GL
|
||||
if (isOGL && !m_fakeGL) {
|
||||
if (aalias) glEnable(GL_MULTISAMPLE);
|
||||
else glDisable(GL_MULTISAMPLE);
|
||||
if (aalias)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
else
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
}
|
||||
#endif
|
||||
fp_size.clear();
|
||||
@@ -476,8 +475,8 @@ void Graphic::canvasPaintEvent() {
|
||||
|
||||
|
||||
void Graphic::canvasMouseMoveEvent(QMouseEvent * e) {
|
||||
isHover = true;
|
||||
curpos = e->pos();
|
||||
isHover = true;
|
||||
curpos = e->pos();
|
||||
curpos_r = canvas2real(curpos);
|
||||
QPointF dp;
|
||||
QString cursorstr = tr("Cursor: ") + pointCoords(curpos_r);
|
||||
@@ -491,38 +490,34 @@ void Graphic::canvasMouseMoveEvent(QMouseEvent * e) {
|
||||
if (gestures) {
|
||||
if (!need_mouse_pan) return;
|
||||
curaction = gaMove;
|
||||
} else
|
||||
if (curaction != gaMove && (e->buttons() & Qt::RightButton) == Qt::RightButton) return;
|
||||
} else if (curaction != gaMove && (e->buttons() & Qt::RightButton) == Qt::RightButton)
|
||||
return;
|
||||
switch (curaction) {
|
||||
case gaZoomInRect:
|
||||
ui->status->setText(tr("Selection") + ": " + pointCoords(startpos_r) + " -> " +
|
||||
pointCoords(curpos_r) + ", " + tr("Size") + ": " + pointCoords(absPoint(curpos_r - startpos_r)));
|
||||
repaintCanvas(true);
|
||||
case gaZoomInRect:
|
||||
ui->status->setText(tr("Selection") + ": " + pointCoords(startpos_r) + " -> " + pointCoords(curpos_r) + ", " + tr("Size") + ": " +
|
||||
pointCoords(absPoint(curpos_r - startpos_r)));
|
||||
repaintCanvas(true);
|
||||
break;
|
||||
case gaZoomRangeX:
|
||||
ui->status->setText(tr("Range") + ": " + QString::number(startpos_r.x(), 'f', 3) +
|
||||
" -> " + QString::number(curpos_r.x(), 'f', 3) + ", " + tr("Length") + ": " +
|
||||
QString::number(qAbs(curpos_r.x() - startpos_r.x()), 'f', 3));
|
||||
repaintCanvas(true);
|
||||
case gaZoomRangeX:
|
||||
ui->status->setText(tr("Range") + ": " + QString::number(startpos_r.x(), 'f', 3) + " -> " + QString::number(curpos_r.x(), 'f', 3) +
|
||||
", " + tr("Length") + ": " + QString::number(qAbs(curpos_r.x() - startpos_r.x()), 'f', 3));
|
||||
repaintCanvas(true);
|
||||
break;
|
||||
case gaZoomRangeY:
|
||||
ui->status->setText(tr("Range") + ": " + QString::number(startpos_r.y(), 'f', 3) +
|
||||
" -> " + QString::number(curpos_r.y(), 'f', 3) + ", " + tr("Length") + ": " +
|
||||
QString::number(qAbs(curpos_r.y() - startpos_r.y()), 'f', 3));
|
||||
repaintCanvas(true);
|
||||
case gaZoomRangeY:
|
||||
ui->status->setText(tr("Range") + ": " + QString::number(startpos_r.y(), 'f', 3) + " -> " + QString::number(curpos_r.y(), 'f', 3) +
|
||||
", " + tr("Length") + ": " + QString::number(qAbs(curpos_r.y() - startpos_r.y()), 'f', 3));
|
||||
repaintCanvas(true);
|
||||
break;
|
||||
case gaMove:
|
||||
dp = e->pos() - prevpos;
|
||||
dp.rx() *= selrect.width() / double(gridborder.x() + 5 - lastw);
|
||||
dp.ry() *= selrect.height() / double(lasth - gridborder.y() - 5);
|
||||
if (e->modifiers() == Qt::ControlModifier)
|
||||
dp.setY(0.);
|
||||
if (e->modifiers() == Qt::ShiftModifier)
|
||||
dp.setX(0.);
|
||||
selrect.translate(dp);
|
||||
totalUpdate();
|
||||
case gaMove:
|
||||
dp = e->pos() - prevpos;
|
||||
dp.rx() *= selrect.width() / double(gridborder.x() + 5 - lastw);
|
||||
dp.ry() *= selrect.height() / double(lasth - gridborder.y() - 5);
|
||||
if (e->modifiers() == Qt::ControlModifier) dp.setY(0.);
|
||||
if (e->modifiers() == Qt::ShiftModifier) dp.setX(0.);
|
||||
selrect.translate(dp);
|
||||
totalUpdate();
|
||||
break;
|
||||
default: break;
|
||||
default: break;
|
||||
}
|
||||
prevpos = e->pos();
|
||||
}
|
||||
@@ -533,14 +528,14 @@ void Graphic::canvasMousePressEvent(QMouseEvent * e) {
|
||||
if (!navigation) return;
|
||||
if (gestures && !need_mouse_pan) return;
|
||||
setGuidesCursor();
|
||||
prevpos = e->pos();
|
||||
startpos = prevpos;
|
||||
prevpos = e->pos();
|
||||
startpos = prevpos;
|
||||
startpos_r = canvas2real(startpos);
|
||||
if (cancel || gestures) return;
|
||||
if (e->button() == QT_MID_BUTTON) curaction = gaMove;
|
||||
if (e->button() == Qt::RightButton) {
|
||||
if (bufferActive) {
|
||||
curpos = startpos;
|
||||
curpos = startpos;
|
||||
curpos_r = canvas2real(curpos);
|
||||
repaintCanvas(true);
|
||||
swapToNormal();
|
||||
@@ -553,16 +548,17 @@ void Graphic::canvasMousePressEvent(QMouseEvent * e) {
|
||||
}
|
||||
}
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
if (e->modifiers() == Qt::ControlModifier) curaction = gaZoomRangeX;
|
||||
else if (e->modifiers() == Qt::ShiftModifier) curaction = gaZoomRangeY;
|
||||
else curaction = gaZoomInRect;
|
||||
if (e->modifiers() == Qt::ControlModifier)
|
||||
curaction = gaZoomRangeX;
|
||||
else if (e->modifiers() == Qt::ShiftModifier)
|
||||
curaction = gaZoomRangeY;
|
||||
else
|
||||
curaction = gaZoomInRect;
|
||||
switch (curaction) {
|
||||
case gaZoomInRect:
|
||||
case gaZoomRangeX:
|
||||
case gaZoomRangeY:
|
||||
swapToBuffer();
|
||||
break;
|
||||
default: break;
|
||||
case gaZoomInRect:
|
||||
case gaZoomRangeX:
|
||||
case gaZoomRangeY: swapToBuffer(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
setCurrentAction(curaction);
|
||||
@@ -588,24 +584,24 @@ void Graphic::canvasMouseReleaseEvent(QMouseEvent * e) {
|
||||
}
|
||||
if (e->button() == Qt::LeftButton && (e->buttons() & Qt::RightButton) != Qt::RightButton) {
|
||||
if (curpos != startpos) {
|
||||
tlp = canvas2real(sr.topLeft());
|
||||
brp = canvas2real(sr.bottomRight());
|
||||
tlp = canvas2real(sr.topLeft());
|
||||
brp = canvas2real(sr.bottomRight());
|
||||
isFit = false;
|
||||
switch (curaction) {
|
||||
case gaZoomInRect:
|
||||
if (sr.width() <= 1 || sr.height() <= 1) break;
|
||||
selrect.setCoords(tlp.x(), brp.y(), brp.x(), tlp.y());
|
||||
setRectToLines();
|
||||
case gaZoomInRect:
|
||||
if (sr.width() <= 1 || sr.height() <= 1) break;
|
||||
selrect.setCoords(tlp.x(), brp.y(), brp.x(), tlp.y());
|
||||
setRectToLines();
|
||||
break;
|
||||
case gaZoomRangeX:
|
||||
if (sr.width() <= 1) break;
|
||||
findGraphicsRect(tlp.x(), brp.x());
|
||||
case gaZoomRangeX:
|
||||
if (sr.width() <= 1) break;
|
||||
findGraphicsRect(tlp.x(), brp.x());
|
||||
break;
|
||||
case gaZoomRangeY:
|
||||
if (sr.height() <= 1) break;
|
||||
findGraphicsRect(0., 0., brp.y(), tlp.y());
|
||||
case gaZoomRangeY:
|
||||
if (sr.height() <= 1) break;
|
||||
findGraphicsRect(0., 0., brp.y(), tlp.y());
|
||||
break;
|
||||
default: return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
swapToNormal();
|
||||
@@ -617,7 +613,7 @@ void Graphic::canvasMouseReleaseEvent(QMouseEvent * e) {
|
||||
}
|
||||
|
||||
|
||||
void Graphic::canvasMouseDoubleClickEvent(QMouseEvent * ) {
|
||||
void Graphic::canvasMouseDoubleClickEvent(QMouseEvent *) {
|
||||
if (!navigation) return;
|
||||
autofit();
|
||||
}
|
||||
@@ -641,11 +637,15 @@ void Graphic::canvasWheelEvent(QWheelEvent * e) {
|
||||
|
||||
|
||||
void Graphic::zoom(float factor) {
|
||||
double wid = canvas->width() - gridborder.x() - margins_.width() - margins_.left(), hei = canvas->height() - gridborder.y() - margins_.height() - margins_.top();
|
||||
double wid = canvas->width() - gridborder.x() - margins_.width() - margins_.left(),
|
||||
hei = canvas->height() - gridborder.y() - margins_.height() - margins_.top();
|
||||
double px = wid / 2, py = hei / 2;
|
||||
px = px / wid * selrect.width() + selrect.x();
|
||||
py = py / hei * selrect.height() + selrect.y();
|
||||
selrect.setRect(px - (px - selrect.x()) * factor, py - (py - selrect.y()) * factor, selrect.width() * factor, selrect.height() * factor);
|
||||
selrect.setRect(px - (px - selrect.x()) * factor,
|
||||
py - (py - selrect.y()) * factor,
|
||||
selrect.width() * factor,
|
||||
selrect.height() * factor);
|
||||
isFit = false;
|
||||
update(true);
|
||||
setRectToLines();
|
||||
@@ -653,12 +653,14 @@ void Graphic::zoom(float factor) {
|
||||
|
||||
|
||||
void Graphic::fullscreen() {
|
||||
if (fullscr) leaveFullscreen();
|
||||
else enterFullscreen();
|
||||
if (fullscr)
|
||||
leaveFullscreen();
|
||||
else
|
||||
enterFullscreen();
|
||||
}
|
||||
|
||||
|
||||
void Graphic::canvasLeaveEvent(QEvent * ) {
|
||||
void Graphic::canvasLeaveEvent(QEvent *) {
|
||||
isHover = false;
|
||||
if (guides) update(true);
|
||||
ui->status->setText(tr("Cursor") + ": ( ; )");
|
||||
@@ -668,8 +670,8 @@ void Graphic::canvasLeaveEvent(QEvent * ) {
|
||||
|
||||
void Graphic::canvasKeyPressEvent(QKeyEvent * e) {
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Escape: leaveFullscreen();
|
||||
default: break;
|
||||
case Qt::Key_Escape: leaveFullscreen();
|
||||
default: break;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -680,7 +682,7 @@ void Graphic::clear() {
|
||||
graphics[i].polyline_pause.clear();
|
||||
graphics[i]._lod.clear();
|
||||
graphics[i]._lod_pause.clear();
|
||||
graphics[i].max_x = 0.;
|
||||
graphics[i].max_x = 0.;
|
||||
graphics[i].cvrect = QRectF();
|
||||
}
|
||||
if (isFit) on_graphic_buttonAutofit_clicked();
|
||||
@@ -725,8 +727,8 @@ void Graphic::setHistorySize(double val) {
|
||||
QPolygonF & pol(graphics[i].polyline);
|
||||
if (pol.isEmpty() || history <= 0.) continue;
|
||||
graphics[i].cvrect = QRectF();
|
||||
x = pol.back().x() - history;
|
||||
for (int j = pol.size() - 2; j >= 0 ; --j)
|
||||
x = pol.back().x() - history;
|
||||
for (int j = pol.size() - 2; j >= 0; --j)
|
||||
if (pol[j].x() < x) {
|
||||
pol.erase(pol.begin(), pol.begin() + j);
|
||||
break;
|
||||
@@ -813,8 +815,8 @@ void Graphic::setButtons(Graphic::Buttons b) {
|
||||
ui->graphic_buttonClose->setVisible(b.testFlag(Close));
|
||||
ui->graphic_checkPause->setVisible(b.testFlag(Pause));
|
||||
ui->graphic_buttonRecord->setVisible(b.testFlag(Record));
|
||||
if (ui->graphic_buttonAutofit ->isVisible() || ui->graphic_checkGrid ->isVisible() || ui->graphic_checkGuides->isVisible() ||
|
||||
ui->graphic_buttonConfigure->isVisible() || ui->graphic_buttonSave->isVisible() || ui->graphic_checkPause ->isVisible())
|
||||
if (ui->graphic_buttonAutofit->isVisible() || ui->graphic_checkGrid->isVisible() || ui->graphic_checkGuides->isVisible() ||
|
||||
ui->graphic_buttonConfigure->isVisible() || ui->graphic_buttonSave->isVisible() || ui->graphic_checkPause->isVisible())
|
||||
ui->verticalSpacer->changeSize(0, 30, QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
else
|
||||
ui->verticalSpacer->changeSize(0, 0, QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
@@ -830,13 +832,13 @@ void Graphic::setButtonsPosition(Graphic::Alignment a) {
|
||||
return;
|
||||
#endif
|
||||
switch (a) {
|
||||
case Graphic::Left:
|
||||
ui->widgetLeft->setLayout(ui->layoutButtons);
|
||||
ui->widgetLeft->show();
|
||||
case Graphic::Left:
|
||||
ui->widgetLeft->setLayout(ui->layoutButtons);
|
||||
ui->widgetLeft->show();
|
||||
break;
|
||||
case Graphic::Right:
|
||||
ui->widgetRight->setLayout(ui->layoutButtons);
|
||||
ui->widgetRight->show();
|
||||
case Graphic::Right:
|
||||
ui->widgetRight->setLayout(ui->layoutButtons);
|
||||
ui->widgetRight->show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -862,7 +864,7 @@ void Graphic::addPoints(const QPolygonF & pts, int graphic, bool update_) {
|
||||
if (graphic >= graphics.size() || graphic < 0 || pts.isEmpty()) return;
|
||||
GraphicType & t(graphics[graphic]);
|
||||
if (!t.cvrect.isNull() && !pause_) {
|
||||
for(const QPointF & p : pts) {
|
||||
for (const QPointF & p: pts) {
|
||||
if (t.cvrect.top() < p.y()) t.cvrect.setTop(p.y());
|
||||
if (t.cvrect.bottom() > p.y()) t.cvrect.setBottom(p.y());
|
||||
if (t.cvrect.right() < p.x()) t.cvrect.setRight(p.x());
|
||||
@@ -870,7 +872,8 @@ void Graphic::addPoints(const QPolygonF & pts, int graphic, bool update_) {
|
||||
}
|
||||
}
|
||||
if (t.polyline.size() == 0) t.max_x = pts.at(0).x();
|
||||
for(const QPointF & p : pts) if (t.max_x < p.x()) t.max_x = p.x();
|
||||
for (const QPointF & p: pts)
|
||||
if (t.max_x < p.x()) t.max_x = p.x();
|
||||
t.polyline << pts;
|
||||
tick(graphic, true, update_);
|
||||
}
|
||||
@@ -881,7 +884,8 @@ void Graphic::addPoints(const QVector<double> & pts, int graphic, bool update_)
|
||||
ps.reserve(pts.size());
|
||||
double stx = 0;
|
||||
if (!graphics[curGraphic].polyline.isEmpty()) stx = graphics[curGraphic].max_x;
|
||||
for (int i=0; i<pts.size(); ++i) ps << QPointF(stx + i*inc_x, pts[i]);
|
||||
for (int i = 0; i < pts.size(); ++i)
|
||||
ps << QPointF(stx + i * inc_x, pts[i]);
|
||||
addPoints(ps, graphic, update_);
|
||||
}
|
||||
|
||||
@@ -899,13 +903,17 @@ void Graphic::setGraphicData(const QVector<QPointF> & g, int graphic, bool updat
|
||||
}
|
||||
t.max_x = t.polyline[0].x();
|
||||
for (int i = 1; i < t.polyline.size(); ++i)
|
||||
if (t.max_x < t.polyline[i].x())
|
||||
t.max_x = t.polyline[i].x();
|
||||
if (t.max_x < t.polyline[i].x()) t.max_x = t.polyline[i].x();
|
||||
tick(graphic, false, update_);
|
||||
}
|
||||
|
||||
|
||||
void Graphic::setGraphicProperties(int graphic, const QString & name, const QColor& color, Qt::PenStyle style, double width, bool visible) {
|
||||
void Graphic::setGraphicProperties(int graphic,
|
||||
const QString & name,
|
||||
const QColor & color,
|
||||
Qt::PenStyle style,
|
||||
double width,
|
||||
bool visible) {
|
||||
if (graphic < 0 || graphic >= graphics.size()) return;
|
||||
graphics[graphic].name = name;
|
||||
graphics[graphic].pen.setColor(color);
|
||||
@@ -924,7 +932,7 @@ void Graphic::addGraphic(const QString & name, const QColor & color, Qt::PenStyl
|
||||
|
||||
void Graphic::setVisualRect(const QRectF & rect) {
|
||||
selrect = rect;
|
||||
isFit = false;
|
||||
isFit = false;
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -962,7 +970,7 @@ void Graphic::exportGraphics(QString filename, QChar decimal_point) {
|
||||
}
|
||||
ts << "\n";
|
||||
bool has_data = true;
|
||||
int ind = 0;
|
||||
int ind = 0;
|
||||
QString line;
|
||||
while (has_data) {
|
||||
has_data = false;
|
||||
@@ -991,8 +999,7 @@ void Graphic::exportGraphics(QString filename, QChar decimal_point) {
|
||||
}
|
||||
++ind;
|
||||
line += "\n";
|
||||
if (has_data)
|
||||
ts << line;
|
||||
if (has_data) ts << line;
|
||||
}
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
@@ -1000,14 +1007,14 @@ void Graphic::exportGraphics(QString filename, QChar decimal_point) {
|
||||
|
||||
void Graphic::setOpenGL(bool on) {
|
||||
#ifdef HAS_GL
|
||||
isOGL = on;
|
||||
isOGL = on;
|
||||
need_createGL = false;
|
||||
if (on && !m_fakeGL) {
|
||||
if (!canvas_gl) {
|
||||
if (!isVisible())
|
||||
need_createGL = true;
|
||||
else {
|
||||
//qDebug() << "create GL on setter";
|
||||
// qDebug() << "create GL on setter";
|
||||
canvas_gl = new UGLWidget();
|
||||
ui->layoutCanvas->addWidget(canvas_gl);
|
||||
connect(canvas_gl, SIGNAL(paintSignal()), this, SLOT(canvasPaintEvent()));
|
||||
@@ -1020,8 +1027,7 @@ void Graphic::setOpenGL(bool on) {
|
||||
canvas = canvas_gl;
|
||||
}
|
||||
} else {
|
||||
if (canvas_gl)
|
||||
canvas_gl->hide();
|
||||
if (canvas_gl) canvas_gl->hide();
|
||||
ui->canvas_raster->show();
|
||||
canvas = ui->canvas_raster;
|
||||
}
|
||||
@@ -1043,7 +1049,9 @@ void Graphic::setGraphicsCount(int arg, bool update) {
|
||||
if (arg < 0) return;
|
||||
while (graphics.size() < arg) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
graphics.append(GraphicType(tr("y(x)"), QColor::fromHsv((graphics.size() * 55) % 360, 255, 255 - QRandomGenerator::global()->generate() % 115)));
|
||||
graphics.append(
|
||||
GraphicType(tr("y(x)"),
|
||||
QColor::fromHsv((graphics.size() * 55) % 360, 255, 255 - QRandomGenerator::global()->generate() % 115)));
|
||||
#else
|
||||
graphics.append(GraphicType(tr("y(x)"), QColor::fromHsv((graphics.size() * 55) % 360, 255, 255 - qrand() % 115)));
|
||||
#endif
|
||||
@@ -1064,7 +1072,7 @@ void Graphic::removeGraphic(int arg, bool update) {
|
||||
}
|
||||
|
||||
|
||||
void Graphic::setCustomGridMarkFuncs(std::function<QString (double)> fx, std::function<QString (double)> fy) {
|
||||
void Graphic::setCustomGridMarkFuncs(std::function<QString(double)> fx, std::function<QString(double)> fy) {
|
||||
func_gridMarkX = fx;
|
||||
func_gridMarkY = fy;
|
||||
}
|
||||
@@ -1073,12 +1081,12 @@ void Graphic::setCustomGridMarkFuncs(std::function<QString (double)> fx, std::fu
|
||||
void Graphic::findGraphicsRect(double start_x, double end_x, double start_y, double end_y) {
|
||||
double cx, cy, maxX, minX, maxY, minY, vx;
|
||||
bool isRangeX = (start_x != end_x), isRangeY = (start_y != end_y);
|
||||
bool can_fast = (start_x == 0 && end_x == 0 && start_y == 0 && end_y == 0);
|
||||
bool can_fast = (start_x == 0 && end_x == 0 && start_y == 0 && end_y == 0);
|
||||
bool anyVisible = false, isTimeLimit = (visible_time > 0.) && !(isRangeX || isRangeY);
|
||||
vx = -DBL_MAX;
|
||||
vx = -DBL_MAX;
|
||||
minY = minX = DBL_MAX;
|
||||
maxY = maxX = -DBL_MAX;
|
||||
foreach (const GraphicType & t, graphics) {
|
||||
foreach(const GraphicType & t, graphics) {
|
||||
if (!t.visible) continue;
|
||||
if (vx < (pause_ ? t.max_x_pause : t.max_x)) vx = (pause_ ? t.max_x_pause : t.max_x);
|
||||
}
|
||||
@@ -1130,8 +1138,14 @@ void Graphic::findGraphicsRect(double start_x, double end_x, double start_y, dou
|
||||
if (maxY < limit_.top()) maxY = limit_.top();
|
||||
if (minX > maxX) qSwap<double>(minX, maxX);
|
||||
if (minY > maxY) qSwap<double>(minY, maxY);
|
||||
if (qAbs<double>(minX - maxX) < 1E-60) {minX -= defaultRect().width()/2; maxX += defaultRect().width()/2;}
|
||||
if (qAbs<double>(minY - maxY) < 1E-60) {minY -= defaultRect().height()/2; maxY += defaultRect().height()/2;}
|
||||
if (qAbs<double>(minX - maxX) < 1E-60) {
|
||||
minX -= defaultRect().width() / 2;
|
||||
maxX += defaultRect().width() / 2;
|
||||
}
|
||||
if (qAbs<double>(minY - maxY) < 1E-60) {
|
||||
minY -= defaultRect().height() / 2;
|
||||
maxY += defaultRect().height() / 2;
|
||||
}
|
||||
if (only_expand_x) {
|
||||
if (minX > eminx) minX = eminx;
|
||||
if (maxX < emaxx) maxX = emaxx;
|
||||
@@ -1140,16 +1154,20 @@ void Graphic::findGraphicsRect(double start_x, double end_x, double start_y, dou
|
||||
if (minY > eminy) minY = eminy;
|
||||
if (maxY < emaxy) maxY = emaxy;
|
||||
}
|
||||
eminx = minX; emaxx = maxX;
|
||||
eminy = minY; emaxy = maxY;
|
||||
if (isRangeX) selrect.setRect(start_x, minY, end_x - start_x, maxY - minY);
|
||||
else if (isRangeY) selrect.setRect(minX, start_y, maxX - minX, end_y - start_y);
|
||||
else grect.setRect(minX, minY, maxX - minX, maxY - minY);
|
||||
eminx = minX;
|
||||
emaxx = maxX;
|
||||
eminy = minY;
|
||||
emaxy = maxY;
|
||||
if (isRangeX)
|
||||
selrect.setRect(start_x, minY, end_x - start_x, maxY - minY);
|
||||
else if (isRangeY)
|
||||
selrect.setRect(minX, start_y, maxX - minX, end_y - start_y);
|
||||
else
|
||||
grect.setRect(minX, minY, maxX - minX, maxY - minY);
|
||||
grect = grect.normalized();
|
||||
if (isFit) {
|
||||
if (visible_time > 0.) {
|
||||
if (grect.width() > visible_time)
|
||||
grect.setLeft(grect.right() - visible_time);
|
||||
if (grect.width() > visible_time) grect.setLeft(grect.right() - visible_time);
|
||||
}
|
||||
selrect = grect;
|
||||
}
|
||||
@@ -1158,28 +1176,29 @@ void Graphic::findGraphicsRect(double start_x, double end_x, double start_y, dou
|
||||
|
||||
|
||||
void Graphic::drawAction() {
|
||||
int wid = canvas->width(), hei = canvas->height() - gridborder.y(), sx = startpos.x(), sy = startpos.y(), cx = curpos.x(), cy = curpos.y();
|
||||
int wid = canvas->width(), hei = canvas->height() - gridborder.y(), sx = startpos.x(), sy = startpos.y(), cx = curpos.x(),
|
||||
cy = curpos.y();
|
||||
painter->setPen(selpen);
|
||||
painter->setBrush(selbrush);
|
||||
switch (curaction) {
|
||||
case gaZoomInRect: {
|
||||
QSizeF rsz = QRectF(startpos_r, curpos_r).normalized().size();
|
||||
painter->drawRect(QRect(startpos, curpos));
|
||||
fp_size = " x " + pointCoords(QPointF(rsz.width(), rsz.height()));
|
||||
} break;
|
||||
case gaZoomRangeX:
|
||||
painter->drawLine(sx, hei, sx, 0);
|
||||
painter->drawLine(cx, hei, cx, 0);
|
||||
painter->fillRect(sx, 0, cx - sx, hei, selbrush);
|
||||
fp_size = " x " + pointCoords(QPointF(qAbs(startpos_r.x() - curpos_r.x()), 0.), true, false);
|
||||
break;
|
||||
case gaZoomRangeY:
|
||||
painter->drawLine(gridborder.x(), sy, wid, sy);
|
||||
painter->drawLine(gridborder.x(), cy, wid, cy);
|
||||
painter->fillRect(gridborder.x(), sy, wid - gridborder.x(), cy - sy, selbrush);
|
||||
fp_size = " x " + pointCoords(QPointF(0., qAbs(startpos_r.y() - curpos_r.y())), false, true);
|
||||
break;
|
||||
default: break;
|
||||
case gaZoomInRect: {
|
||||
QSizeF rsz = QRectF(startpos_r, curpos_r).normalized().size();
|
||||
painter->drawRect(QRect(startpos, curpos));
|
||||
fp_size = " x " + pointCoords(QPointF(rsz.width(), rsz.height()));
|
||||
} break;
|
||||
case gaZoomRangeX:
|
||||
painter->drawLine(sx, hei, sx, 0);
|
||||
painter->drawLine(cx, hei, cx, 0);
|
||||
painter->fillRect(sx, 0, cx - sx, hei, selbrush);
|
||||
fp_size = " x " + pointCoords(QPointF(qAbs(startpos_r.x() - curpos_r.x()), 0.), true, false);
|
||||
break;
|
||||
case gaZoomRangeY:
|
||||
painter->drawLine(gridborder.x(), sy, wid, sy);
|
||||
painter->drawLine(gridborder.x(), cy, wid, cy);
|
||||
painter->fillRect(gridborder.x(), sy, wid - gridborder.x(), cy - sy, selbrush);
|
||||
fp_size = " x " + pointCoords(QPointF(0., qAbs(startpos_r.y() - curpos_r.y())), false, true);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1192,12 +1211,14 @@ void Graphic::drawGrid() {
|
||||
QPair<QString, QString> str;
|
||||
|
||||
range = selrect.bottom() - selrect.top();
|
||||
if (grad_y == Graphic::Auto) step = splitRange(range, hei / gridy / font_sz.height() / 1.4);
|
||||
else step = gridy;
|
||||
if (grad_y == Graphic::Auto)
|
||||
step = splitRange(range, hei / gridy / font_sz.height() / 1.4);
|
||||
else
|
||||
step = gridy;
|
||||
start = roundTo(canvas2realY(-hei), step) - step;
|
||||
py = start + step;
|
||||
cy = 0;
|
||||
cx = gbx - 5;
|
||||
py = start + step;
|
||||
cy = 0;
|
||||
cx = gbx - 5;
|
||||
grid_pen.setWidth(qMax<int>(qMax<int>(qRound(thick / 1.4), 1), grid_pen.width()));
|
||||
#if QT_VERSION_MAJOR >= 5
|
||||
grid_pen.setCosmetic(true);
|
||||
@@ -1257,10 +1278,12 @@ void Graphic::drawGrid() {
|
||||
range = selrect.right() - selrect.left();
|
||||
QString df;
|
||||
if (axis_type_x == Graphic::Numeric) {
|
||||
if (grad_x == Graphic::Auto) step = splitRange(range, wid / gridx / font_sz.width() * 1.4);
|
||||
else step = gridx;
|
||||
if (grad_x == Graphic::Auto)
|
||||
step = splitRange(range, wid / gridx / font_sz.width() * 1.4);
|
||||
else
|
||||
step = gridx;
|
||||
start = roundTo(canvas2realX(right), step);
|
||||
px = start + step;
|
||||
px = start + step;
|
||||
if (step > 0.) {
|
||||
cnt = 1000;
|
||||
while (cnt-- > 0) {
|
||||
@@ -1300,10 +1323,12 @@ void Graphic::drawGrid() {
|
||||
} else {
|
||||
int dt_add[DateComponentCount];
|
||||
int dt_add_lo[DateComponentCount];
|
||||
for (int i = 0; i < DateComponentCount; ++i) dt_add_lo[i] = dt_add[i] = 0;
|
||||
for (int i = 0; i < DateComponentCount; ++i)
|
||||
dt_add_lo[i] = dt_add[i] = 0;
|
||||
DateFormats formats;
|
||||
step = splitRangeDate(range, wid / gridx / font_sz.width() / 1.5, formats, dt_add);
|
||||
for (int i = 0; i < DateComponentCount - 1; ++i) dt_add_lo[i + 1] = dt_add[i];
|
||||
for (int i = 0; i < DateComponentCount - 1; ++i)
|
||||
dt_add_lo[i + 1] = dt_add[i];
|
||||
bool is_years = formats.center.isEmpty();
|
||||
if (step > 0.) {
|
||||
int up_y = cy - font_sz.height() * 2;
|
||||
@@ -1312,7 +1337,7 @@ void Graphic::drawGrid() {
|
||||
int ddx = 0, pcx = 0;
|
||||
QDateTime cd = QDateTime::fromMSecsSinceEpoch(canvas2realX(gbx) * grid_numbers_x), cdp, cdc, cdl, cdlp;
|
||||
QString ds;
|
||||
//qDebug() << step << range << int(wid / gridx / font_sz.width() * 1.4) << cd;
|
||||
// qDebug() << step << range << int(wid / gridx / font_sz.width() * 1.4) << cd;
|
||||
if (!is_years) {
|
||||
roundDateTime(cd, dt_add);
|
||||
cdp = cdl = cdlp = cd;
|
||||
@@ -1322,13 +1347,13 @@ void Graphic::drawGrid() {
|
||||
cd.setTime(QTime(0, 0, 0));
|
||||
cd.setDate(QDate(roundTo(cd.date().year(), dt_add[6]) - dt_add[6], 1, 1));
|
||||
}
|
||||
//qDebug() << cd << cur_scl[0] << cur_scl[1] << cur_scl[2] << cur_scl[3] << cur_scl[4] << cur_scl[5] << cur_scl[6];
|
||||
// qDebug() << cd << cur_scl[0] << cur_scl[1] << cur_scl[2] << cur_scl[3] << cur_scl[4] << cur_scl[5] << cur_scl[6];
|
||||
struct Anchor {
|
||||
int x_start, x_end;
|
||||
QDateTime date;
|
||||
};
|
||||
QVector<Anchor> areas_ce, areas_lo;
|
||||
cnt = 1000;
|
||||
cnt = 1000;
|
||||
int area_start = gbx, area_start_lo = gbx;
|
||||
pcx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x);
|
||||
while (cnt-- > 0) {
|
||||
@@ -1341,16 +1366,16 @@ void Graphic::drawGrid() {
|
||||
if (cx < gbx) continue;
|
||||
if (cdp != cdc) {
|
||||
int cxc = real2canvasX(cdc.toMSecsSinceEpoch() / grid_numbers_x);
|
||||
//qDebug() << cx << cxc << ddx << pcx;
|
||||
// qDebug() << cx << cxc << ddx << pcx;
|
||||
if ((qAbs(cxc - cx) < ddx) && (cx != cxc)) need_text = false;
|
||||
areas_ce << Anchor{area_start, qMin(cxc, right), cdp};
|
||||
area_start = areas_ce.back().x_end;
|
||||
cd = cdl = cdp = cdc;
|
||||
cx = cxc;
|
||||
cx = cxc;
|
||||
roundDateTime(cdl, dt_add_lo);
|
||||
if (cdlp != cdl) {
|
||||
areas_lo << Anchor{area_start_lo, qMin(cxc, right), cdlp};
|
||||
cdlp = cdl;
|
||||
cdlp = cdl;
|
||||
area_start_lo = areas_lo.back().x_end;
|
||||
}
|
||||
} else {
|
||||
@@ -1372,11 +1397,9 @@ void Graphic::drawGrid() {
|
||||
}
|
||||
}
|
||||
if (!is_years) {
|
||||
if (area_start < right)
|
||||
areas_ce << Anchor{area_start, right, cdc};
|
||||
if (area_start_lo < right)
|
||||
areas_lo << Anchor{area_start_lo, right, cdl};
|
||||
//qDebug() << areas_lo.size() << formats.upper << areas_lo[0].date;
|
||||
if (area_start < right) areas_ce << Anchor{area_start, right, cdc};
|
||||
if (area_start_lo < right) areas_lo << Anchor{area_start_lo, right, cdl};
|
||||
// qDebug() << areas_lo.size() << formats.upper << areas_lo[0].date;
|
||||
painter->setPen(grid_pen);
|
||||
for (const auto & a: areas_ce) {
|
||||
painter->drawLine(a.x_start, hei + 5, a.x_start, ce_y);
|
||||
@@ -1389,12 +1412,12 @@ void Graphic::drawGrid() {
|
||||
painter->setFont(nf);
|
||||
auto pfm = painter->fontMetrics();
|
||||
for (const auto & a: areas_ce) {
|
||||
ds = a.date.toString(formats.center);
|
||||
ds = a.date.toString(formats.center);
|
||||
auto str_rect = pfm.boundingRect(ds);
|
||||
painter->drawText(a.x_start + (a.x_end - a.x_start - str_rect.width()) / 2, ce_y, ds);
|
||||
}
|
||||
for (const auto & a: areas_lo) {
|
||||
ds = a.date.toString(formats.lower);
|
||||
ds = a.date.toString(formats.lower);
|
||||
auto str_rect = pfm.boundingRect(ds);
|
||||
painter->drawText(a.x_start + (a.x_end - a.x_start - str_rect.width()) / 2, lo_y, ds);
|
||||
}
|
||||
@@ -1426,7 +1449,7 @@ QPair<QString, QString> Graphic::gridMark(double v) const {
|
||||
v = 1.;
|
||||
p += 1;
|
||||
}
|
||||
ret.first = QString::fromUtf8("%1·10").arg(v);
|
||||
ret.first = QString::fromUtf8("%1·10").arg(v);
|
||||
ret.second = QString::number(p);
|
||||
} else
|
||||
ret.first = QString::number(v, 'g', 8);
|
||||
@@ -1437,31 +1460,30 @@ QPair<QString, QString> Graphic::gridMark(double v) const {
|
||||
void Graphic::fillDateFormats() {
|
||||
date_formats.clear();
|
||||
QString tr_ms = tr("ms"), tr_s = tr("s"), tr_m = tr("m"), tr_h = tr("h");
|
||||
auto trFunc = [&](const DateFormats & src)->DateFormats{
|
||||
auto trFunc = [&](const DateFormats & src) -> DateFormats {
|
||||
DateFormats ret;
|
||||
ret.upper = QString(src.upper ).replace("%1", tr_ms).replace("%2", tr_s).replace("%3", tr_m).replace("%4", tr_h);
|
||||
ret.upper = QString(src.upper).replace("%1", tr_ms).replace("%2", tr_s).replace("%3", tr_m).replace("%4", tr_h);
|
||||
ret.center = QString(src.center).replace("%1", tr_ms).replace("%2", tr_s).replace("%3", tr_m).replace("%4", tr_h);
|
||||
ret.lower = QString(src.lower ).replace("%1", tr_ms).replace("%2", tr_s).replace("%3", tr_m).replace("%4", tr_h);
|
||||
ret.lower = QString(src.lower).replace("%1", tr_ms).replace("%2", tr_s).replace("%3", tr_m).replace("%4", tr_h);
|
||||
return ret;
|
||||
};
|
||||
date_formats << trFunc(DateFormats{"zzz '%1'", "h '%4' mm '%3' ss '%2'", "yyyy MMM dd(ddd)"});
|
||||
date_formats << trFunc(DateFormats{"ss '%2'" , "h '%4' mm '%3'" , "yyyy MMM dd(ddd)"});
|
||||
date_formats << trFunc(DateFormats{"mm '%3'" , "h '%4'" , "yyyy MMM dd(ddd)"});
|
||||
date_formats << trFunc(DateFormats{"h '%4'" , "dd(ddd)" , "yyyy MMM" });
|
||||
date_formats << trFunc(DateFormats{"dd(ddd)" , "MMM" , "yyyy" });
|
||||
date_formats << trFunc(DateFormats{"MMM" , "yyyy" , "" });
|
||||
date_formats << trFunc(DateFormats{"yyyy" , "" , "" });
|
||||
date_formats << trFunc(DateFormats{"ss '%2'", "h '%4' mm '%3'", "yyyy MMM dd(ddd)"});
|
||||
date_formats << trFunc(DateFormats{"mm '%3'", "h '%4'", "yyyy MMM dd(ddd)"});
|
||||
date_formats << trFunc(DateFormats{"h '%4'", "dd(ddd)", "yyyy MMM"});
|
||||
date_formats << trFunc(DateFormats{"dd(ddd)", "MMM", "yyyy"});
|
||||
date_formats << trFunc(DateFormats{"MMM", "yyyy", ""});
|
||||
date_formats << trFunc(DateFormats{"yyyy", "", ""});
|
||||
}
|
||||
|
||||
|
||||
void Graphic::drawGraphics() {
|
||||
if (isHover)
|
||||
ui->status->setText(tr("Cursor: ") + pointCoords(canvas2real(QPointF(curpos))));
|
||||
if (isHover) ui->status->setText(tr("Cursor: ") + pointCoords(canvas2real(QPointF(curpos))));
|
||||
QPointF srp = -selrect.topLeft();
|
||||
double sclx, scly, wid = canvas->width(), hei = canvas->height();
|
||||
int cwid = (wid - gridborder.x() - margins_.left() - margins_.width());
|
||||
sclx = cwid / selrect.width();
|
||||
scly = (hei - gridborder.y() - margins_.top() - margins_.height()) / selrect.height();
|
||||
sclx = cwid / selrect.width();
|
||||
scly = (hei - gridborder.y() - margins_.top() - margins_.height()) / selrect.height();
|
||||
painter->setClipping(true);
|
||||
painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y()));
|
||||
painter->translate(gridborder.x() + margins_.left(), hei - gridborder.y() - margins_.top());
|
||||
@@ -1478,23 +1500,23 @@ void Graphic::drawGraphics() {
|
||||
QVector<QPolygonF> & src_lod(pause_ ? t._lod_pause : t._lod);
|
||||
int lod = 0;
|
||||
if (m_LODOptimization) {
|
||||
int gpcnt = src_pol.size();
|
||||
int gpcnt = src_pol.size();
|
||||
qreal range = src_pol.back().x() - src_pol.front().x();
|
||||
qreal ppp = (gpcnt * selrect.width() / qMax(range, 1.E-9) / cwid);
|
||||
lod = qBound<int>(0, qFloor(log2(ppp) - 1), src_lod.size());
|
||||
//qDebug() << "draw lod" << lod << src_lod[lod - 1].size();
|
||||
qreal ppp = (gpcnt * selrect.width() / qMax(range, 1.E-9) / cwid);
|
||||
lod = qBound<int>(0, qFloor(log2(ppp) - 1), src_lod.size());
|
||||
// qDebug() << "draw lod" << lod << src_lod[lod - 1].size();
|
||||
}
|
||||
t.last_lod = lod;
|
||||
QPolygonF & rpol(lod == 0 ? src_pol : src_lod[lod - 1]);
|
||||
int ind_start = -1, ind_end = -1;
|
||||
if (m_LODOptimization) {
|
||||
qreal xs = selrect.left(), xe = selrect.right(), _offset = 2. / cwid * selrect.width();
|
||||
xs -= _offset; xe += _offset;
|
||||
xs -= _offset;
|
||||
xe += _offset;
|
||||
for (int i = 0; i < rpol.size(); ++i) {
|
||||
qreal px = rpol[i].x();
|
||||
if (px < xs) continue;
|
||||
if (ind_start < 0)
|
||||
ind_start = qMax(0, i - 1);
|
||||
if (ind_start < 0) ind_start = qMax(0, i - 1);
|
||||
if (px > xe && ind_end < 0) {
|
||||
ind_end = qMin(rpol.size(), i + 1);
|
||||
break;
|
||||
@@ -1502,10 +1524,10 @@ void Graphic::drawGraphics() {
|
||||
}
|
||||
if (ind_start < 0) ind_start = 0;
|
||||
if (ind_end < 0) ind_end = rpol.size();
|
||||
//qDebug() << "bound" << ind_start << ind_end << rpol.size();
|
||||
// qDebug() << "bound" << ind_start << ind_end << rpol.size();
|
||||
} else {
|
||||
ind_start = 0;
|
||||
ind_end = rpol.size();
|
||||
ind_end = rpol.size();
|
||||
}
|
||||
int polsize = ind_end - ind_start;
|
||||
if (polsize > 0) {
|
||||
@@ -1513,13 +1535,15 @@ void Graphic::drawGraphics() {
|
||||
if (m_LODOptimization && polsize < rpol.size()) {
|
||||
cpol.resize(polsize);
|
||||
memcpy(cpol.data(), &(rpol[ind_start]), polsize * sizeof(QPointF));
|
||||
//qDebug() << "copy" << polsize;
|
||||
// qDebug() << "copy" << polsize;
|
||||
} else {
|
||||
cpol = rpol;
|
||||
}
|
||||
pen = t.pen;
|
||||
if (qRound(pen.widthF()) == pen.widthF()) pen.setWidth(pen.width()*thick);
|
||||
else pen.setWidthF(pen.widthF()*thick);
|
||||
if (qRound(pen.widthF()) == pen.widthF())
|
||||
pen.setWidth(pen.width() * thick);
|
||||
else
|
||||
pen.setWidthF(pen.widthF() * thick);
|
||||
pen.setCosmetic(true);
|
||||
if (t.lines) {
|
||||
painter->setPen(pen);
|
||||
@@ -1530,8 +1554,10 @@ void Graphic::drawGraphics() {
|
||||
painter->drawPolyline(mat.map(cpol));
|
||||
}
|
||||
if (t.points) {
|
||||
if (qRound(t.pointWidth) == t.pointWidth) pen.setWidth(qRound(t.pointWidth*thick));
|
||||
else pen.setWidthF(t.pointWidth*thick);
|
||||
if (qRound(t.pointWidth) == t.pointWidth)
|
||||
pen.setWidth(qRound(t.pointWidth * thick));
|
||||
else
|
||||
pen.setWidthF(t.pointWidth * thick);
|
||||
painter->setPen(pen);
|
||||
painter->drawPoints(mat.map(cpol));
|
||||
}
|
||||
@@ -1549,9 +1575,9 @@ QString Graphic::pointCoords(QPointF point, bool x, bool y) {
|
||||
else
|
||||
ret +=
|
||||
#if QT_VERSION_MAJOR <= 5
|
||||
QDateTime::fromMSecsSinceEpoch(point.x()).toString(Qt::SystemLocaleShortDate);
|
||||
QDateTime::fromMSecsSinceEpoch(point.x()).toString(Qt::SystemLocaleShortDate);
|
||||
#else
|
||||
locale().toString(QDateTime::fromMSecsSinceEpoch(point.x()), QLocale::ShortFormat);
|
||||
locale().toString(QDateTime::fromMSecsSinceEpoch(point.x()), QLocale::ShortFormat);
|
||||
#endif
|
||||
}
|
||||
if (y) {
|
||||
@@ -1575,11 +1601,11 @@ void Graphic::drawGuides() {
|
||||
painter->resetTransform();
|
||||
painter->setClipping(true);
|
||||
painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y()));
|
||||
QPoint apos = curpos;
|
||||
QPoint apos = curpos;
|
||||
QPointF rpos = canvas2real(apos);
|
||||
QString str;
|
||||
str = pointCoords(rpos) + fp_size;
|
||||
bool trace_found = false;
|
||||
str = pointCoords(rpos) + fp_size;
|
||||
bool trace_found = false;
|
||||
auto trace_axis_func = [&](bool on_x, double cursor) {
|
||||
if (curTrace >= 0 && curTrace < graphics.size()) {
|
||||
auto & t(graphics[curTrace]);
|
||||
@@ -1594,13 +1620,13 @@ void Graphic::drawGuides() {
|
||||
dist = qAbs<double>((on_x ? pol[i].x() : pol[i].y()) - cursor);
|
||||
if (min_dist > dist || min_dist < 0) {
|
||||
min_dist = dist;
|
||||
index = i;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
if (index >= 0) {
|
||||
rpos = pol[index];
|
||||
apos = real2canvas(rpos).toPoint();
|
||||
str = pointCoords(pol[index]) + fp_size;
|
||||
rpos = pol[index];
|
||||
apos = real2canvas(rpos).toPoint();
|
||||
str = pointCoords(pol[index]) + fp_size;
|
||||
trace_found = true;
|
||||
emit graphicTraceEvent(curTrace, rpos);
|
||||
}
|
||||
@@ -1610,7 +1636,7 @@ void Graphic::drawGuides() {
|
||||
auto trace_free_func = [&](QPointF cursor) {
|
||||
double min_dist = -1;
|
||||
int gr = -1, mag_dist = fontHeight(this) * 2;
|
||||
QPointF point, scale = getScale(), dp;
|
||||
QPointF point, scale = getScale(), dp;
|
||||
for (int g = 0; g < graphics.size(); ++g) {
|
||||
auto & t(graphics[g]);
|
||||
if (t.visible) {
|
||||
@@ -1627,34 +1653,27 @@ void Graphic::drawGuides() {
|
||||
dist = QVector2D(dp).lengthSquared();
|
||||
if (min_dist > dist || min_dist < 0) {
|
||||
min_dist = dist;
|
||||
gr = g;
|
||||
rpos = point;
|
||||
gr = g;
|
||||
rpos = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gr >= 0) {
|
||||
apos = real2canvas(rpos).toPoint();
|
||||
str = " " + graphics[gr].name + ": " + pointCoords(rpos) + fp_size;
|
||||
apos = real2canvas(rpos).toPoint();
|
||||
str = " " + graphics[gr].name + ": " + pointCoords(rpos) + fp_size;
|
||||
trace_found = true;
|
||||
emit graphicTraceEvent(gr, rpos);
|
||||
}
|
||||
};
|
||||
switch (floating_axis_type) {
|
||||
case TraceXY:
|
||||
trace_free_func(rpos);
|
||||
break;
|
||||
case TraceX:
|
||||
trace_axis_func(true, rpos.x());
|
||||
break;
|
||||
case TraceY:
|
||||
trace_axis_func(false, rpos.y());
|
||||
break;
|
||||
case TraceXY: trace_free_func(rpos); break;
|
||||
case TraceX: trace_axis_func(true, rpos.x()); break;
|
||||
case TraceY: trace_axis_func(false, rpos.y()); break;
|
||||
default: break;
|
||||
}
|
||||
if (was_trace && !trace_found)
|
||||
emit graphicTraceEvent(-1, QPointF());
|
||||
if (was_trace && !trace_found) emit graphicTraceEvent(-1, QPointF());
|
||||
was_trace = trace_found;
|
||||
painter->drawLine(0, apos.y(), wid, apos.y());
|
||||
painter->drawLine(apos.x(), 0, apos.x(), hei);
|
||||
@@ -1678,7 +1697,7 @@ void Graphic::drawPause() {
|
||||
painter->resetTransform();
|
||||
painter->translate(canvas->width() - icon_pause_b.width() - 6, 6);
|
||||
double o = (0.5 - pause_phase) * 2;
|
||||
painter->setOpacity(o*o);
|
||||
painter->setOpacity(o * o);
|
||||
painter->drawImage(0, 0, icon_pause_b);
|
||||
painter->setOpacity(1.);
|
||||
painter->drawImage(0, 0, icon_pause_f);
|
||||
@@ -1689,11 +1708,11 @@ void Graphic::drawPause() {
|
||||
double roundToSteps(double value, const QVector<double> & steps) {
|
||||
double ret = value, min_err = -1.;
|
||||
for (double v: steps) {
|
||||
double sv = qRound64(value / v) * v;
|
||||
double sv = qRound64(value / v) * v;
|
||||
double err = qAbs<double>(value - sv);
|
||||
if (min_err < 0 || min_err > err) {
|
||||
min_err = err;
|
||||
ret = sv;
|
||||
ret = sv;
|
||||
}
|
||||
}
|
||||
if (ret < steps[0]) ret = steps[0];
|
||||
@@ -1706,7 +1725,7 @@ double roundToNearest(double value, const QVector<double> & values) {
|
||||
double err = qAbs<double>(value - v);
|
||||
if (min_err < 0 || min_err > err) {
|
||||
min_err = err;
|
||||
ret = v;
|
||||
ret = v;
|
||||
}
|
||||
}
|
||||
if (ret < values[0]) ret = values[0];
|
||||
@@ -1717,13 +1736,13 @@ double roundToNearest(double value, const QVector<double> & values) {
|
||||
double Graphic::splitRange(double range, int count) {
|
||||
double digits, step, tln;
|
||||
range = qAbs<double>(range);
|
||||
tln = qFloor(qLn(range) / LN10);
|
||||
tln = qFloor(qLn(range) / LN10);
|
||||
for (int i = 0; i <= 5; ++i) {
|
||||
digits = qPow(10., tln - i);
|
||||
step = qRound(range / count / digits);
|
||||
step = qRound(range / count / digits);
|
||||
if (step > 0.) {
|
||||
digits = qPow(10., tln - i - 1);
|
||||
step = qRound(range / count / digits);
|
||||
step = qRound(range / count / digits);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1733,22 +1752,32 @@ double Graphic::splitRange(double range, int count) {
|
||||
|
||||
|
||||
double Graphic::splitRangeDate(double range, int count, DateFormats & formats, int step[7]) {
|
||||
static const qint64
|
||||
to_sec = 1000LL,
|
||||
to_min = 1000LL * 60,
|
||||
to_hour = 1000LL * 60 * 60,
|
||||
to_day = 1000LL * 60 * 60 * 24,
|
||||
to_month = 1000LL * 60 * 60 * 24 * 30,
|
||||
to_year = 1000LL * 60 * 60 * 24 * 30 * 12;
|
||||
double ret = splitRange(range, count);
|
||||
static const qint64 to_sec = 1000LL, to_min = 1000LL * 60, to_hour = 1000LL * 60 * 60, to_day = 1000LL * 60 * 60 * 24,
|
||||
to_month = 1000LL * 60 * 60 * 24 * 30, to_year = 1000LL * 60 * 60 * 24 * 30 * 12;
|
||||
double ret = splitRange(range, count);
|
||||
int format_index = DateYears;
|
||||
if (ret < to_sec / 1 ) {format_index = DateMSecs ; step[DateMSecs ] = qRound64(ret);}
|
||||
else if (ret < to_min / 2 ) {format_index = DateSecs ; step[DateSecs ] = roundToNearest(ret / to_sec , {1, 2, 5, 10, 15, 20, 30});}
|
||||
else if (ret < to_hour ) {format_index = DateMinutes; step[DateMinutes] = roundToNearest(ret / to_min , {1, 2, 5, 10, 15, 20, 30});}
|
||||
else if (ret < to_day ) {format_index = DateHours ; step[DateHours ] = roundToNearest(ret / to_hour , {1, 2, 3, 4, 6, 8, 12});}
|
||||
else if (ret < to_month / 1.6) {format_index = DateDays ; step[DateDays ] = roundToNearest(ret / to_day , {1, 2, 5, 10});}
|
||||
else if (ret < to_year ) {format_index = DateMonths ; step[DateMonths ] = roundToNearest(ret / to_month, {1, 2, 3, 4, 6});}
|
||||
else {format_index = DateYears ; step[DateYears ] = qRound64(ret / to_year);}
|
||||
if (ret < to_sec / 1) {
|
||||
format_index = DateMSecs;
|
||||
step[DateMSecs] = qRound64(ret);
|
||||
} else if (ret < to_min / 2) {
|
||||
format_index = DateSecs;
|
||||
step[DateSecs] = roundToNearest(ret / to_sec, {1, 2, 5, 10, 15, 20, 30});
|
||||
} else if (ret < to_hour) {
|
||||
format_index = DateMinutes;
|
||||
step[DateMinutes] = roundToNearest(ret / to_min, {1, 2, 5, 10, 15, 20, 30});
|
||||
} else if (ret < to_day) {
|
||||
format_index = DateHours;
|
||||
step[DateHours] = roundToNearest(ret / to_hour, {1, 2, 3, 4, 6, 8, 12});
|
||||
} else if (ret < to_month / 1.6) {
|
||||
format_index = DateDays;
|
||||
step[DateDays] = roundToNearest(ret / to_day, {1, 2, 5, 10});
|
||||
} else if (ret < to_year) {
|
||||
format_index = DateMonths;
|
||||
step[DateMonths] = roundToNearest(ret / to_month, {1, 2, 3, 4, 6});
|
||||
} else {
|
||||
format_index = DateYears;
|
||||
step[DateYears] = qRound64(ret / to_year);
|
||||
}
|
||||
formats = date_formats[format_index];
|
||||
return ret;
|
||||
}
|
||||
@@ -1761,25 +1790,35 @@ double Graphic::roundTo(double value, double round_to) {
|
||||
|
||||
|
||||
void Graphic::roundDateTime(QDateTime & dt, int * c) {
|
||||
QDate d(dt.date()); QTime t(dt.time());
|
||||
if (c[DateMSecs ] != 0) t.setHMS(t.hour(), t.minute(), t.second());
|
||||
if (c[DateSecs ] != 0) t.setHMS(t.hour(), t.minute(), 0);
|
||||
QDate d(dt.date());
|
||||
QTime t(dt.time());
|
||||
if (c[DateMSecs] != 0) t.setHMS(t.hour(), t.minute(), t.second());
|
||||
if (c[DateSecs] != 0) t.setHMS(t.hour(), t.minute(), 0);
|
||||
if (c[DateMinutes] != 0) t.setHMS(t.hour(), 0, 0);
|
||||
if (c[DateHours ] != 0) {t.setHMS(0, 0, 0); d.setDate(d.year(), d.month(), d.day());}
|
||||
if (c[DateDays ] != 0) {t.setHMS(0, 0, 0); d.setDate(d.year(), d.month(), 1);}
|
||||
if (c[DateMonths ] != 0 || c[DateYears] != 0) {t.setHMS(0, 0, 0); d.setDate(d.year(), 1, 1);}
|
||||
if (c[DateHours] != 0) {
|
||||
t.setHMS(0, 0, 0);
|
||||
d.setDate(d.year(), d.month(), d.day());
|
||||
}
|
||||
if (c[DateDays] != 0) {
|
||||
t.setHMS(0, 0, 0);
|
||||
d.setDate(d.year(), d.month(), 1);
|
||||
}
|
||||
if (c[DateMonths] != 0 || c[DateYears] != 0) {
|
||||
t.setHMS(0, 0, 0);
|
||||
d.setDate(d.year(), 1, 1);
|
||||
}
|
||||
dt = QDateTime(d, t);
|
||||
}
|
||||
|
||||
|
||||
void Graphic::addDateTime(QDateTime & dt, int * c, qint64 mul) {
|
||||
if (c[DateMSecs ] != 0) dt = dt.addMSecs (mul * c[DateMSecs ]);
|
||||
if (c[DateSecs ] != 0) dt = dt.addSecs (mul * c[DateSecs ]);
|
||||
if (c[DateMinutes] != 0) dt = dt.addSecs (mul * c[DateMinutes] * 60);
|
||||
if (c[DateHours ] != 0) dt = dt.addSecs (mul * c[DateHours ] * 60 * 60);
|
||||
if (c[DateDays ] != 0) dt = dt.addDays (mul * c[DateDays ]);
|
||||
if (c[DateMonths ] != 0) dt = dt.addMonths(mul * c[DateMonths ]);
|
||||
if (c[DateYears ] != 0) dt = dt.addYears (mul * c[DateYears ]);
|
||||
if (c[DateMSecs] != 0) dt = dt.addMSecs(mul * c[DateMSecs]);
|
||||
if (c[DateSecs] != 0) dt = dt.addSecs(mul * c[DateSecs]);
|
||||
if (c[DateMinutes] != 0) dt = dt.addSecs(mul * c[DateMinutes] * 60);
|
||||
if (c[DateHours] != 0) dt = dt.addSecs(mul * c[DateHours] * 60 * 60);
|
||||
if (c[DateDays] != 0) dt = dt.addDays(mul * c[DateDays]);
|
||||
if (c[DateMonths] != 0) dt = dt.addMonths(mul * c[DateMonths]);
|
||||
if (c[DateYears] != 0) dt = dt.addYears(mul * c[DateYears]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1813,7 +1852,7 @@ double Graphic::real2canvasY(double py) const {
|
||||
|
||||
QPolygonF Graphic::real2canvas(const QPolygonF & real_polygon) const {
|
||||
QPolygonF ret;
|
||||
for (int i=0; i<real_polygon.size(); ++i)
|
||||
for (int i = 0; i < real_polygon.size(); ++i)
|
||||
ret << real2canvas(real_polygon[i]);
|
||||
return ret;
|
||||
}
|
||||
@@ -1821,7 +1860,7 @@ QPolygonF Graphic::real2canvas(const QPolygonF & real_polygon) const {
|
||||
|
||||
QPolygonF Graphic::canvas2real(const QPolygonF & canvas_polygon) const {
|
||||
QPolygonF ret;
|
||||
for (int i=0; i<canvas_polygon.size(); ++i)
|
||||
for (int i = 0; i < canvas_polygon.size(); ++i)
|
||||
ret << canvas2real(canvas_polygon[i]);
|
||||
return ret;
|
||||
}
|
||||
@@ -1830,21 +1869,11 @@ QPolygonF Graphic::canvas2real(const QPolygonF & canvas_polygon) const {
|
||||
void Graphic::setCurrentAction(GraphicAction action) {
|
||||
curaction = action;
|
||||
switch (action) {
|
||||
case gaNone:
|
||||
setGuidesCursor();
|
||||
break;
|
||||
case gaZoomInRect:
|
||||
setCanvasCursor(Qt::CrossCursor);
|
||||
break;
|
||||
case gaZoomRangeX:
|
||||
setCanvasCursor(Qt::SplitHCursor);
|
||||
break;
|
||||
case gaZoomRangeY:
|
||||
setCanvasCursor(Qt::SplitVCursor);
|
||||
break;
|
||||
case gaMove:
|
||||
setCanvasCursor(Qt::SizeAllCursor);
|
||||
break;
|
||||
case gaNone: setGuidesCursor(); break;
|
||||
case gaZoomInRect: setCanvasCursor(Qt::CrossCursor); break;
|
||||
case gaZoomRangeX: setCanvasCursor(Qt::SplitHCursor); break;
|
||||
case gaZoomRangeY: setCanvasCursor(Qt::SplitVCursor); break;
|
||||
case gaMove: setCanvasCursor(Qt::SizeAllCursor); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1852,8 +1881,7 @@ void Graphic::setCurrentAction(GraphicAction action) {
|
||||
void Graphic::setCanvasCursor(QCursor cursor) {
|
||||
ui->canvas_raster->setCursor(cursor);
|
||||
#ifdef HAS_GL
|
||||
if (canvas_gl)
|
||||
canvas_gl->setCursor(cursor);
|
||||
if (canvas_gl) canvas_gl->setCursor(cursor);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1883,28 +1911,42 @@ void Graphic::swapToBuffer() {
|
||||
void Graphic::setRectToLines() {
|
||||
is_lines_update = true;
|
||||
if (line_x_min.isVisible() && line_x_max.isVisible() && line_y_min.isVisible() && line_y_max.isVisible()) {
|
||||
line_x_min.blockSignals(true); line_x_max.blockSignals(true); line_y_min.blockSignals(true); line_y_max.blockSignals(true);
|
||||
line_x_min.blockSignals(true);
|
||||
line_x_max.blockSignals(true);
|
||||
line_y_min.blockSignals(true);
|
||||
line_y_max.blockSignals(true);
|
||||
if (!line_x_min.hasFocus()) {
|
||||
if (isFit) line_x_min.setValue(grect.left());
|
||||
else line_x_min.setValue(selrect.left());
|
||||
if (isFit)
|
||||
line_x_min.setValue(grect.left());
|
||||
else
|
||||
line_x_min.setValue(selrect.left());
|
||||
}
|
||||
if (!line_x_max.hasFocus()) {
|
||||
if(isFit) line_x_max.setValue(grect.right());
|
||||
else line_x_max.setValue(selrect.right());
|
||||
if (isFit)
|
||||
line_x_max.setValue(grect.right());
|
||||
else
|
||||
line_x_max.setValue(selrect.right());
|
||||
}
|
||||
if (!line_y_min.hasFocus()) {
|
||||
if(isFit) line_y_min.setValue(grect.bottom());
|
||||
else line_y_min.setValue(selrect.bottom());
|
||||
if (isFit)
|
||||
line_y_min.setValue(grect.bottom());
|
||||
else
|
||||
line_y_min.setValue(selrect.bottom());
|
||||
}
|
||||
if (!line_y_max.hasFocus()) {
|
||||
if(isFit) line_y_max.setValue(grect.top());
|
||||
else line_y_max.setValue(selrect.top());
|
||||
if (isFit)
|
||||
line_y_max.setValue(grect.top());
|
||||
else
|
||||
line_y_max.setValue(selrect.top());
|
||||
}
|
||||
line_x_min.setDefaultText(QString::number(grect.left()).toUpper());
|
||||
line_x_max.setDefaultText(QString::number(grect.right()).toUpper());
|
||||
line_y_min.setDefaultText(QString::number(grect.bottom()).toUpper());
|
||||
line_y_max.setDefaultText(QString::number(grect.top()).toUpper());
|
||||
line_x_min.blockSignals(false); line_x_max.blockSignals(false); line_y_min.blockSignals(false); line_y_max.blockSignals(false);
|
||||
line_x_min.blockSignals(false);
|
||||
line_x_max.blockSignals(false);
|
||||
line_y_min.blockSignals(false);
|
||||
line_y_max.blockSignals(false);
|
||||
}
|
||||
is_lines_update = false;
|
||||
}
|
||||
@@ -1925,10 +1967,8 @@ void Graphic::tick(int index, bool slide, bool update_) {
|
||||
/// TODO: [Graphic] fast autofit while addPoint(double y, ...)
|
||||
if (!t.cvrect.isNull()) {
|
||||
QPointF fp(t.polyline.first());
|
||||
if (qFuzzyCompare(t.cvrect.left(), fp.x()) ||
|
||||
qFuzzyCompare(t.cvrect.right(), fp.x()) ||
|
||||
qFuzzyCompare(t.cvrect.top(), fp.y()) ||
|
||||
qFuzzyCompare(t.cvrect.bottom(), fp.y())) {
|
||||
if (qFuzzyCompare(t.cvrect.left(), fp.x()) || qFuzzyCompare(t.cvrect.right(), fp.x()) ||
|
||||
qFuzzyCompare(t.cvrect.top(), fp.y()) || qFuzzyCompare(t.cvrect.bottom(), fp.y())) {
|
||||
t.cvrect = QRectF();
|
||||
}
|
||||
}
|
||||
@@ -1955,48 +1995,51 @@ void Graphic::calcLOD(int index) {
|
||||
GraphicType & t(graphics[index]);
|
||||
t._lod.clear();
|
||||
int pcnt = t.polyline.size();
|
||||
//qDebug() << "calcLOD" << index;
|
||||
// qDebug() << "calcLOD" << index;
|
||||
while (pcnt >= 10) {
|
||||
QPolygonF & pl(t._lod.isEmpty() ? t.polyline : t._lod.back());
|
||||
t._lod.append(QPolygonF());
|
||||
QPolygonF & cl(t._lod.back());
|
||||
cl << pl.front();
|
||||
int qcnt = (pl.size() + 1) / 4;
|
||||
pcnt = qcnt * 2 + 2;
|
||||
int pc = 4;
|
||||
int qcnt = (pl.size() + 1) / 4;
|
||||
pcnt = qcnt * 2 + 2;
|
||||
int pc = 4;
|
||||
qreal mx[2] = {0., 0.}, my[2] = {0., 0.}, my_x[2] = {0., 0.}, px, py;
|
||||
for (int i = 0; i < qcnt; ++i) {
|
||||
int j = i*4 + 1;
|
||||
int j = i * 4 + 1;
|
||||
if (i == qcnt - 1) pc = pl.size() - j - 1;
|
||||
mx[0] = mx[1] = my_x[0] = my_x[1] = pl[j].x(); my[0] = my[1] = pl[j].y();
|
||||
mx[0] = mx[1] = my_x[0] = my_x[1] = pl[j].x();
|
||||
my[0] = my[1] = pl[j].y();
|
||||
for (int k = 1; k < pc; ++k) {
|
||||
px = pl[j + k].x(); py = pl[j + k].y();
|
||||
mx[0] = qMin(mx[0], px); mx[1] = qMax(mx[1], px);
|
||||
px = pl[j + k].x();
|
||||
py = pl[j + k].y();
|
||||
mx[0] = qMin(mx[0], px);
|
||||
mx[1] = qMax(mx[1], px);
|
||||
if (my[0] > py) {
|
||||
my[0] = py;
|
||||
my[0] = py;
|
||||
my_x[0] = px;
|
||||
}
|
||||
if (my[1] < py) {
|
||||
my[1] = py;
|
||||
my[1] = py;
|
||||
my_x[1] = px;
|
||||
}
|
||||
}
|
||||
qreal dx =(mx[1] - mx[0]) / 4., cx = (mx[1] + mx[0]) / 2.;
|
||||
qreal dx = (mx[1] - mx[0]) / 4., cx = (mx[1] + mx[0]) / 2.;
|
||||
if (my_x[1] >= my_x[0])
|
||||
cl << QPointF(cx - dx, my[0]) << QPointF(cx + dx, my[1]);
|
||||
else
|
||||
cl << QPointF(cx - dx, my[1]) << QPointF(cx + dx, my[0]);
|
||||
}
|
||||
cl << pl.back();
|
||||
//qDebug() << "lod" << t._lod.size() << "->" << cl.size();
|
||||
// qDebug() << "lod" << t._lod.size() << "->" << cl.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Graphic::on_graphic_buttonAutofit_clicked() {
|
||||
isFit = true;
|
||||
isFit = true;
|
||||
bool isEmpty = true;
|
||||
foreach (const GraphicType & t, graphics) {
|
||||
foreach(const GraphicType & t, graphics) {
|
||||
const QPolygonF & pol(pause_ ? t.polyline_pause : t.polyline);
|
||||
if (!pol.isEmpty()) {
|
||||
isEmpty = false;
|
||||
@@ -2046,23 +2089,29 @@ void Graphic::on_graphic_buttonConfigure_clicked() {
|
||||
grid_pen = QPen(conf->ui->colorGrid->color(), conf->ui->spinWidthGrid->value(), (Qt::PenStyle)conf->ui->comboStyleGrid->currentIndex());
|
||||
back_color = conf->ui->colorBackground->color();
|
||||
text_color = conf->ui->colorText->color();
|
||||
grad_x = conf->ui->checkGridAutoX->isChecked() ? Auto : Fixed;
|
||||
grad_y = conf->ui->checkGridAutoY->isChecked() ? Auto : Fixed;
|
||||
gridx = conf->ui->spinGridStepX->value();
|
||||
gridy = conf->ui->spinGridStepY->value();
|
||||
grad_x = conf->ui->checkGridAutoX->isChecked() ? Auto : Fixed;
|
||||
grad_y = conf->ui->checkGridAutoY->isChecked() ? Auto : Fixed;
|
||||
gridx = conf->ui->spinGridStepX->value();
|
||||
gridy = conf->ui->spinGridStepY->value();
|
||||
setOpenGL(conf->ui->checkOGL->isChecked());
|
||||
setAntialiasing(conf->ui->checkAAlias->isChecked());
|
||||
setBorderInputsVisible(conf->ui->checkInputs->isChecked());
|
||||
setStatusVisible(conf->ui->checkStatus->isChecked());
|
||||
setLegendVisible(conf->ui->checkLegend->isChecked());
|
||||
setMargins(conf->ui->spinMarginL->value(), conf->ui->spinMarginR->value(), conf->ui->spinMarginT->value(), conf->ui->spinMarginB->value());
|
||||
setMargins(conf->ui->spinMarginL->value(),
|
||||
conf->ui->spinMarginR->value(),
|
||||
conf->ui->spinMarginT->value(),
|
||||
conf->ui->spinMarginB->value());
|
||||
updateLegend();
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void Graphic::on_graphic_buttonSave_clicked() {
|
||||
QString f = QFileDialog::getSaveFileName(this, tr("Save Image"), ppath, "PNG(*.png);;JPEG(*.jpg *.jpeg);;BMP(*.bmp);;TIFF(*.tiff *.tif);;PPM(*.ppm)");
|
||||
QString f = QFileDialog::getSaveFileName(this,
|
||||
tr("Save Image"),
|
||||
ppath,
|
||||
"PNG(*.png);;JPEG(*.jpg *.jpeg);;BMP(*.bmp);;TIFF(*.tiff *.tif);;PPM(*.ppm)");
|
||||
if (f.isEmpty()) return;
|
||||
saveImage(f);
|
||||
}
|
||||
@@ -2072,7 +2121,8 @@ void Graphic::on_graphic_buttonExport_clicked() {
|
||||
QString f = QFileDialog::getSaveFileName(this, tr("Export graphics"), ppath, "CSV(*.csv)");
|
||||
if (f.isEmpty()) return;
|
||||
QStringList items;
|
||||
items << "." << ",";
|
||||
items << "."
|
||||
<< ",";
|
||||
bool ok;
|
||||
QString item = QInputDialog::getItem(this, tr("Select decimal point"), tr("Decimal point:"), items, 0, false, &ok);
|
||||
if (ok && !item.isEmpty()) exportGraphics(f, item.front());
|
||||
@@ -2092,15 +2142,17 @@ void Graphic::on_graphic_buttonRecord_clicked(bool checked) {
|
||||
qApp->setOverrideCursor(Qt::BusyCursor);
|
||||
GifWriter gif_writer;
|
||||
int frame_delay = 10;
|
||||
if (GifBegin(&gif_writer, f.toUtf8(), static_cast<uint32_t>(record_imgs.first().width()),
|
||||
static_cast<uint32_t>(record_imgs.first().height()),
|
||||
static_cast<uint32_t>(frame_delay))) {
|
||||
for (const QImage & im : record_imgs) {
|
||||
if (GifBegin(&gif_writer,
|
||||
f.toUtf8(),
|
||||
static_cast<uint32_t>(record_imgs.first().width()),
|
||||
static_cast<uint32_t>(record_imgs.first().height()),
|
||||
static_cast<uint32_t>(frame_delay))) {
|
||||
for (const QImage & im: record_imgs) {
|
||||
if (!GifWriteFrame(&gif_writer,
|
||||
im.convertToFormat(QImage::Format_RGBA8888).constBits(),
|
||||
static_cast<uint32_t>(im.width()),
|
||||
static_cast<uint32_t>(im.height()),
|
||||
static_cast<uint32_t>(frame_delay))) {
|
||||
im.convertToFormat(QImage::Format_RGBA8888).constBits(),
|
||||
static_cast<uint32_t>(im.width()),
|
||||
static_cast<uint32_t>(im.height()),
|
||||
static_cast<uint32_t>(frame_delay))) {
|
||||
GifEnd(&gif_writer);
|
||||
qDebug() << "GifWriteFrame ERROR";
|
||||
}
|
||||
@@ -2127,8 +2179,10 @@ void Graphic::updateLegend(bool es) {
|
||||
pix.fill(back_color);
|
||||
QPainter p(&pix);
|
||||
QPen pen = graphics[i].pen;
|
||||
if (qRound(pen.widthF()) == pen.widthF()) pen.setWidth(pen.width()*thick);
|
||||
else pen.setWidthF(pen.widthF()*thick);
|
||||
if (qRound(pen.widthF()) == pen.widthF())
|
||||
pen.setWidth(pen.width() * thick);
|
||||
else
|
||||
pen.setWidthF(pen.widthF() * thick);
|
||||
p.setPen(pen);
|
||||
p.drawLine(0, pix.height() / 2, pix.width(), pix.height() / 2);
|
||||
p.end();
|
||||
@@ -2139,7 +2193,7 @@ void Graphic::updateLegend(bool es) {
|
||||
return;
|
||||
}
|
||||
leg_update = false;
|
||||
int ps = 100;
|
||||
int ps = 100;
|
||||
for (int r = 0; r < ui->layoutLegend->rowCount(); ++r)
|
||||
for (int c = 0; c < ui->layoutLegend->columnCount(); ++c) {
|
||||
QLayoutItem * li = ui->layoutLegend->itemAtPosition(r, c);
|
||||
@@ -2167,33 +2221,36 @@ void Graphic::updateLegend(bool es) {
|
||||
if (cps > ps) ps = cps;
|
||||
}
|
||||
LegendScrollArea * leg_sa = (LegendScrollArea *)ui->scrollLegend->layout()->itemAt(0)->widget();
|
||||
int maxcol = qMax<int>(leg_sa->width() / ps - 1, 1);
|
||||
int maxcol = qMax<int>(leg_sa->width() / ps - 1, 1);
|
||||
int row = 0, col = 0;
|
||||
bool lv = ui->scrollLegend->isVisibleTo(this);
|
||||
ui->scrollLegend->hide();
|
||||
for (int i = 0; i < graphics.size(); i++) {
|
||||
ui->layoutLegend->addWidget(graphics[i].pb,row,col);
|
||||
ui->layoutLegend->addWidget(graphics[i].pb, row, col);
|
||||
QCheckBox * check = graphics[i].pb;
|
||||
check->show();
|
||||
if (leg_sa->minimum_hei == 0) {
|
||||
leg_sa->minimum_hei = ui->widgetLegend->sizeHint().height();
|
||||
/*#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
QTimer::singleShot(0, this, [this,leg_sa,check](){
|
||||
leg_sa->minimum_hei = check->sizeHint().height();
|
||||
leg_sa->updateGeometry();
|
||||
qDebug() << leg_sa->minimum_hei << ui->widgetLegend->sizeHint();
|
||||
});
|
||||
#else
|
||||
leg_sa->minimum_hei = check->sizeHint().height();
|
||||
#endif*/
|
||||
/*#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
QTimer::singleShot(0, this, [this,leg_sa,check](){
|
||||
leg_sa->minimum_hei = check->sizeHint().height();
|
||||
leg_sa->updateGeometry();
|
||||
qDebug() << leg_sa->minimum_hei << ui->widgetLegend->sizeHint();
|
||||
});
|
||||
#else
|
||||
leg_sa->minimum_hei = check->sizeHint().height();
|
||||
#endif*/
|
||||
}
|
||||
col++;
|
||||
if (col > maxcol) {col = 0; row++;}
|
||||
if (col > maxcol) {
|
||||
col = 0;
|
||||
row++;
|
||||
}
|
||||
}
|
||||
ui->gridLayout->invalidate();
|
||||
ui->scrollLegend->setVisible(lv);
|
||||
leg_sa->updateGeometry();
|
||||
//ui->gridLayout->invalidate();
|
||||
// ui->gridLayout->invalidate();
|
||||
leg_update = true;
|
||||
if (es) emit graphicSettingsChanged();
|
||||
}
|
||||
@@ -2212,24 +2269,30 @@ void Graphic::updateLegendChecks() {
|
||||
|
||||
void Graphic::graphicVisibleChange(bool checked) {
|
||||
if (visible_update) return;
|
||||
QCheckBox * cb = qobject_cast<QCheckBox*>(sender());
|
||||
int i = cb->property("graphic_num").toInt();
|
||||
QCheckBox * cb = qobject_cast<QCheckBox *>(sender());
|
||||
int i = cb->property("graphic_num").toInt();
|
||||
graphics[i].visible = checked;
|
||||
if (isFit) on_graphic_buttonAutofit_clicked();
|
||||
else {update();}
|
||||
if (isFit)
|
||||
on_graphic_buttonAutofit_clicked();
|
||||
else {
|
||||
update();
|
||||
}
|
||||
emit graphicSettingsChanged();
|
||||
}
|
||||
|
||||
|
||||
void Graphic::graphicAllVisibleChange(bool checked) {
|
||||
visible_update = true;
|
||||
for (int i=0; i<graphics.size(); i++) {
|
||||
for (int i = 0; i < graphics.size(); i++) {
|
||||
graphics[i].visible = checked;
|
||||
graphics[i].pb->setChecked(checked);
|
||||
}
|
||||
visible_update = false;
|
||||
if (isFit) on_graphic_buttonAutofit_clicked();
|
||||
else {update();}
|
||||
if (isFit)
|
||||
on_graphic_buttonAutofit_clicked();
|
||||
else {
|
||||
update();
|
||||
}
|
||||
emit graphicSettingsChanged();
|
||||
}
|
||||
|
||||
@@ -2319,23 +2382,22 @@ bool Graphic::legendVisible() const {
|
||||
|
||||
|
||||
QByteArray Graphic::save() {
|
||||
// QByteArray ba;
|
||||
// QDataStream s(&ba, QIODevice::ReadWrite);
|
||||
// s << openGL() << antialiasing() << borderInputsVisible() << statusVisible() << legendVisible();
|
||||
// s << graphics;
|
||||
// return ba;
|
||||
// QByteArray ba;
|
||||
// QDataStream s(&ba, QIODevice::ReadWrite);
|
||||
// s << openGL() << antialiasing() << borderInputsVisible() << statusVisible() << legendVisible();
|
||||
// s << graphics;
|
||||
// return ba;
|
||||
|
||||
// version '2':
|
||||
// version '2':
|
||||
ChunkStream cs;
|
||||
cs.add(1, antialiasing()).add(2, openGL()).add(3, borderInputsVisible()).add(4, statusVisible()).add(5, legendVisible());
|
||||
cs.add(6, backgroundColor()).add(7, textColor()).add(8, margins());
|
||||
cs.add(9, gridPen()).add(10, graduationX()).add(11, graduationY()).add(12, graduationStepX()).add(13, graduationStepY());
|
||||
cs.add(14, graphics);
|
||||
cs.add(15, isFit).add(16, visualRect());
|
||||
if (backgroundColor() == palette().color(QPalette::Base) &&
|
||||
textColor() == palette().color(QPalette::WindowText) &&
|
||||
gridColor() == palette().color(QPalette::Disabled, QPalette::WindowText))
|
||||
cs.add(17, true);
|
||||
if (backgroundColor() == palette().color(QPalette::Base) && textColor() == palette().color(QPalette::WindowText) &&
|
||||
gridColor() == palette().color(QPalette::Disabled, QPalette::WindowText))
|
||||
cs.add(17, true);
|
||||
return cs.data().prepend('2');
|
||||
}
|
||||
|
||||
@@ -2343,8 +2405,8 @@ QByteArray Graphic::save() {
|
||||
void Graphic::load(QByteArray ba) {
|
||||
if (ba.isEmpty()) return;
|
||||
char ver = ba[0];
|
||||
switch(ver) {
|
||||
case '2': {// version '2':
|
||||
switch (ver) {
|
||||
case '2': { // version '2':
|
||||
ba.remove(0, 1);
|
||||
QRectF vrect;
|
||||
ChunkStream cs(ba);
|
||||
@@ -2356,35 +2418,47 @@ void Graphic::load(QByteArray ba) {
|
||||
case 3: setBorderInputsVisible(cs.getData<bool>()); break;
|
||||
case 4: setStatusVisible(cs.getData<bool>()); break;
|
||||
case 5: setLegendVisible(cs.getData<bool>()); break;
|
||||
case 6: if (!def_colors) setBackgroundColor(cs.getData<QColor>()); break;
|
||||
case 7: if (!def_colors) setTextColor(cs.getData<QColor>()); break;
|
||||
case 6:
|
||||
if (!def_colors) setBackgroundColor(cs.getData<QColor>());
|
||||
break;
|
||||
case 7:
|
||||
if (!def_colors) setTextColor(cs.getData<QColor>());
|
||||
break;
|
||||
case 8: setMargins(cs.getData<QRect>()); break;
|
||||
case 9: if (!def_colors) setGridPen(cs.getData<QPen>()); break;
|
||||
case 9:
|
||||
if (!def_colors) setGridPen(cs.getData<QPen>());
|
||||
break;
|
||||
case 10: setGraduationX(cs.getData<Graduation>()); break;
|
||||
case 11: setGraduationY(cs.getData<Graduation>()); break;
|
||||
case 12: setGraduationStepX(cs.getData<double>()); break;
|
||||
case 13: setGraduationStepY(cs.getData<double>()); break;
|
||||
case 14: graphics = cs.getData<QVector<GraphicType> >(); break;
|
||||
case 14: graphics = cs.getData<QVector<GraphicType>>(); break;
|
||||
case 15: isFit = cs.getData<bool>(); break;
|
||||
case 16: vrect = cs.getData<QRectF>(); break;
|
||||
case 17: if(cs.getData<bool>()) {
|
||||
setTextColor(palette().color(QPalette::WindowText));
|
||||
setGridPen(QPen(palette().color(QPalette::Disabled, QPalette::WindowText), 0., Qt::DotLine));
|
||||
setBackgroundColor(palette().color(QPalette::Base));
|
||||
def_colors = true;
|
||||
} break;
|
||||
case 17:
|
||||
if (cs.getData<bool>()) {
|
||||
setTextColor(palette().color(QPalette::WindowText));
|
||||
setGridPen(QPen(palette().color(QPalette::Disabled, QPalette::WindowText), 0., Qt::DotLine));
|
||||
setBackgroundColor(palette().color(QPalette::Base));
|
||||
def_colors = true;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (!isFit) setVisualRect(vrect);
|
||||
} break;
|
||||
default: {// old version 0:
|
||||
default: { // old version 0:
|
||||
QDataStream s(ba);
|
||||
bool a;
|
||||
s >> a; setOpenGL(a);
|
||||
s >> a; setAntialiasing(a);
|
||||
s >> a; setBorderInputsVisible(a);
|
||||
s >> a; setStatusVisible(a);
|
||||
s >> a;
|
||||
setOpenGL(a);
|
||||
s >> a;
|
||||
setAntialiasing(a);
|
||||
s >> a;
|
||||
setBorderInputsVisible(a);
|
||||
s >> a;
|
||||
setStatusVisible(a);
|
||||
s >> a;
|
||||
s >> graphics;
|
||||
setLegendVisible(a);
|
||||
@@ -2403,7 +2477,8 @@ void Graphic::setCaption(const QString & str) {
|
||||
void Graphic::setGraphicVisible(bool visible, int index) {
|
||||
graphics[index].visible = visible;
|
||||
updateLegendChecks();
|
||||
if (isFit) on_graphic_buttonAutofit_clicked();
|
||||
if (isFit)
|
||||
on_graphic_buttonAutofit_clicked();
|
||||
else if (aupdate)
|
||||
update();
|
||||
}
|
||||
@@ -2431,7 +2506,7 @@ void Graphic::setLegendVisible(bool visible) {
|
||||
ui->scrollLegend->setVisible(visible);
|
||||
ui->graphic_checkLegend->setChecked(visible);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
QTimer::singleShot(0, this, [this](){updateLegend();});
|
||||
QTimer::singleShot(0, this, [this]() { updateLegend(); });
|
||||
#else
|
||||
updateLegend();
|
||||
#endif
|
||||
|
||||
+440
-229
@@ -1,46 +1,47 @@
|
||||
/*
|
||||
QAD - Qt ADvanced
|
||||
QAD - Qt ADvanced
|
||||
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHIC_H
|
||||
#define GRAPHIC_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QMouseEvent>
|
||||
#include "evalspinbox.h"
|
||||
#include "graphic_conf.h"
|
||||
#include "qad_graphic_export.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDebug>
|
||||
#include <QGridLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QElapsedTimer>
|
||||
#include <QTranslator>
|
||||
#include <QFileDialog>
|
||||
#include <QGestureEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QMenu>
|
||||
#include <qmath.h>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QTranslator>
|
||||
#include <QWidget>
|
||||
#include <float.h>
|
||||
#include "graphic_conf.h"
|
||||
#include "evalspinbox.h"
|
||||
#include "qad_graphic_export.h"
|
||||
#include <qmath.h>
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class Graphic;
|
||||
class Graphic;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +52,7 @@ class GraphicPlugin;
|
||||
Q_DECLARE_METATYPE(QVector<QPointF>)
|
||||
|
||||
|
||||
class QAD_GRAPHIC_EXPORT Graphic: public QFrame
|
||||
{
|
||||
class QAD_GRAPHIC_EXPORT Graphic: public QFrame {
|
||||
Q_OBJECT
|
||||
Q_FLAGS(Buttons)
|
||||
Q_ENUMS(Alignment Graduation AxisType FloatingAxisType)
|
||||
@@ -127,164 +127,262 @@ public:
|
||||
Graphic(QWidget * parent = 0);
|
||||
virtual ~Graphic();
|
||||
|
||||
typedef QVector<QVector<QPointF> > GraphicsData;
|
||||
enum GraphicAction {gaNone, gaZoomInRect, gaZoomRangeX, gaZoomRangeY, gaMove};
|
||||
enum Button {NoButtons = 0x0,
|
||||
AllButtons = 0xFFFFFFFF,
|
||||
Autofit = 0x01,
|
||||
Grid = 0x02,
|
||||
CursorAxis = 0x04,
|
||||
Fullscreen = 0x20,
|
||||
BorderInputs = 0x40,
|
||||
Legend = 0x80,
|
||||
Configure = 0x100,
|
||||
Save = 0x200,
|
||||
Export = 0x400,
|
||||
Clear = 0x800,
|
||||
Close = 0x1000,
|
||||
Pause = 0x2000,
|
||||
Record = 0x4000,
|
||||
StandartButtons = 0x2BFF
|
||||
};
|
||||
enum Alignment {Left, Right};
|
||||
enum Graduation {Auto, Fixed};
|
||||
enum AxisType {Numeric, DateTime};
|
||||
enum FloatingAxisType {Free, TraceXY, TraceX, TraceY};
|
||||
typedef QVector<QVector<QPointF>> GraphicsData;
|
||||
enum GraphicAction {
|
||||
gaNone,
|
||||
gaZoomInRect,
|
||||
gaZoomRangeX,
|
||||
gaZoomRangeY,
|
||||
gaMove
|
||||
};
|
||||
enum Button {
|
||||
NoButtons = 0x0,
|
||||
AllButtons = 0xFFFFFFFF,
|
||||
Autofit = 0x01,
|
||||
Grid = 0x02,
|
||||
CursorAxis = 0x04,
|
||||
Fullscreen = 0x20,
|
||||
BorderInputs = 0x40,
|
||||
Legend = 0x80,
|
||||
Configure = 0x100,
|
||||
Save = 0x200,
|
||||
Export = 0x400,
|
||||
Clear = 0x800,
|
||||
Close = 0x1000,
|
||||
Pause = 0x2000,
|
||||
Record = 0x4000,
|
||||
StandartButtons = 0x2BFF
|
||||
};
|
||||
enum Alignment {
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
enum Graduation {
|
||||
Auto,
|
||||
Fixed
|
||||
};
|
||||
enum AxisType {
|
||||
Numeric,
|
||||
DateTime
|
||||
};
|
||||
enum FloatingAxisType {
|
||||
Free,
|
||||
TraceXY,
|
||||
TraceX,
|
||||
TraceY
|
||||
};
|
||||
Q_DECLARE_FLAGS(Buttons, Button)
|
||||
|
||||
QString caption() const;
|
||||
QString labelX() const {return label_x;}
|
||||
QString labelY() const {return label_y;}
|
||||
QString graphicName() const {return graphics[curGraphic].name;}
|
||||
QString graphicName(int index) const {return graphics[index].name;}
|
||||
QColor backgroundColor() const {return back_color;}
|
||||
QColor textColor() const {return text_color;}
|
||||
QColor graphicColor() const {return graphics[curGraphic].pen.color();}
|
||||
QColor graphicColor(int index) const {return graphics[index].pen.color();}
|
||||
QColor gridColor() const {return grid_pen.color();}
|
||||
QColor selectionColor() const {return selpen.color();}
|
||||
Qt::PenStyle graphicStyle() const {return graphics[curGraphic].pen.style();}
|
||||
Qt::PenStyle graphicStyle(int index) const {return graphics[index].pen.style();}
|
||||
Qt::PenStyle gridStyle() const {return grid_pen.style();}
|
||||
Qt::PenStyle selectionStyle() const {return selpen.style();}
|
||||
double graphicLineWidth() const {return graphics[curGraphic].pen.widthF();}
|
||||
double graphicLineWidth(int index) const {return graphics[index].pen.widthF();}
|
||||
double graphicPointWidth() const {return graphics[curGraphic].pointWidth;}
|
||||
double graphicPointWidth(int index) const {return graphics[index].pointWidth;}
|
||||
QColor graphicFillColor() const {return graphics[curGraphic].fill_color;}
|
||||
QColor graphicFillColor(int index) const {return graphics[index].fill_color;}
|
||||
bool graphicVisible() const {return graphics[curGraphic].visible;}
|
||||
bool graphicVisible(int index) const {return graphics[index].visible;}
|
||||
bool graphicLinesEnabled() const {return graphics[curGraphic].lines;}
|
||||
bool graphicLinesEnabled(int index) const {return graphics[index].lines;}
|
||||
bool graphicPointsEnabled() const {return graphics[curGraphic].points;}
|
||||
bool graphicPointsEnabled(int index) const {return graphics[index].points;}
|
||||
bool graphicFillEnabled() const {return graphics[curGraphic].fill;}
|
||||
bool graphicFillEnabled(int index) const {return graphics[index].fill;}
|
||||
QPen graphicPen() const {return graphics[curGraphic].pen;}
|
||||
QPen graphicPen(int index) const {return graphics[index].pen;}
|
||||
QPen gridPen() const {return grid_pen;}
|
||||
QPen selectionPen() const {return selpen;}
|
||||
QBrush selectionBrush() const {return selbrush;}
|
||||
bool navigationEnabled() const {return navigation;}
|
||||
bool openGL() const {return isOGL;}
|
||||
bool antialiasing() const {return aalias;}
|
||||
bool autoUpdate() const {return aupdate;}
|
||||
bool gridEnabled() const {return grid;}
|
||||
QString labelX() const { return label_x; }
|
||||
QString labelY() const { return label_y; }
|
||||
QString graphicName() const { return graphics[curGraphic].name; }
|
||||
QString graphicName(int index) const { return graphics[index].name; }
|
||||
QColor backgroundColor() const { return back_color; }
|
||||
QColor textColor() const { return text_color; }
|
||||
QColor graphicColor() const { return graphics[curGraphic].pen.color(); }
|
||||
QColor graphicColor(int index) const { return graphics[index].pen.color(); }
|
||||
QColor gridColor() const { return grid_pen.color(); }
|
||||
QColor selectionColor() const { return selpen.color(); }
|
||||
Qt::PenStyle graphicStyle() const { return graphics[curGraphic].pen.style(); }
|
||||
Qt::PenStyle graphicStyle(int index) const { return graphics[index].pen.style(); }
|
||||
Qt::PenStyle gridStyle() const { return grid_pen.style(); }
|
||||
Qt::PenStyle selectionStyle() const { return selpen.style(); }
|
||||
double graphicLineWidth() const { return graphics[curGraphic].pen.widthF(); }
|
||||
double graphicLineWidth(int index) const { return graphics[index].pen.widthF(); }
|
||||
double graphicPointWidth() const { return graphics[curGraphic].pointWidth; }
|
||||
double graphicPointWidth(int index) const { return graphics[index].pointWidth; }
|
||||
QColor graphicFillColor() const { return graphics[curGraphic].fill_color; }
|
||||
QColor graphicFillColor(int index) const { return graphics[index].fill_color; }
|
||||
bool graphicVisible() const { return graphics[curGraphic].visible; }
|
||||
bool graphicVisible(int index) const { return graphics[index].visible; }
|
||||
bool graphicLinesEnabled() const { return graphics[curGraphic].lines; }
|
||||
bool graphicLinesEnabled(int index) const { return graphics[index].lines; }
|
||||
bool graphicPointsEnabled() const { return graphics[curGraphic].points; }
|
||||
bool graphicPointsEnabled(int index) const { return graphics[index].points; }
|
||||
bool graphicFillEnabled() const { return graphics[curGraphic].fill; }
|
||||
bool graphicFillEnabled(int index) const { return graphics[index].fill; }
|
||||
QPen graphicPen() const { return graphics[curGraphic].pen; }
|
||||
QPen graphicPen(int index) const { return graphics[index].pen; }
|
||||
QPen gridPen() const { return grid_pen; }
|
||||
QPen selectionPen() const { return selpen; }
|
||||
QBrush selectionBrush() const { return selbrush; }
|
||||
bool navigationEnabled() const { return navigation; }
|
||||
bool openGL() const { return isOGL; }
|
||||
bool antialiasing() const { return aalias; }
|
||||
bool autoUpdate() const { return aupdate; }
|
||||
bool gridEnabled() const { return grid; }
|
||||
bool borderInputsVisible() const;
|
||||
bool statusVisible() const;
|
||||
bool legendVisible() const;
|
||||
bool paused() const {return pause_;}
|
||||
bool onlyExpandY() const {return only_expand_y;}
|
||||
bool onlyExpandX() const {return only_expand_x;}
|
||||
bool gesturesNavigation() const {return gestures;}
|
||||
bool LODOptimization() const {return m_LODOptimization;}
|
||||
bool isAutofitted() const {return isFit;}
|
||||
int currentGraphic() const {return curGraphic;}
|
||||
int currentTraceGraphic() const {return curTrace;}
|
||||
int graphicsCount() const {return graphics.size();}
|
||||
Graphic::Buttons buttons() const {return buttons_;}
|
||||
Graphic::Alignment buttonsPosition() const {return align;}
|
||||
double historySize() const {return history;}
|
||||
double maxVisibleTime() const {return visible_time;}
|
||||
double autoXIncrement() const {return inc_x;}
|
||||
QRectF visualRect() const {return selrect;}
|
||||
QRectF defaultRect() const {return def_rect;}
|
||||
QRectF limit() const {return limit_;}
|
||||
QRect margins() const {return margins_;}
|
||||
int minimumRepaintInterval() const {return min_repaint_int;}
|
||||
double gridNumbersMultiplierX() const {return grid_numbers_x;}
|
||||
double gridNumbersMultiplierY() const {return grid_numbers_y;}
|
||||
Graduation graduationX() const {return grad_x;}
|
||||
Graduation graduationY() const {return grad_y;}
|
||||
double graduationStepX() const {return gridx;}
|
||||
double graduationStepY() const {return gridy;}
|
||||
AxisType axisType() const {return axis_type_x;}
|
||||
FloatingAxisType floatingAxisType() const {return floating_axis_type;}
|
||||
QVector<QPointF> graphicData() const {return graphics[curGraphic].polyline;}
|
||||
QVector<QPointF> graphicData(int index) const {return graphics[index].polyline;}
|
||||
bool paused() const { return pause_; }
|
||||
bool onlyExpandY() const { return only_expand_y; }
|
||||
bool onlyExpandX() const { return only_expand_x; }
|
||||
bool gesturesNavigation() const { return gestures; }
|
||||
bool LODOptimization() const { return m_LODOptimization; }
|
||||
bool isAutofitted() const { return isFit; }
|
||||
int currentGraphic() const { return curGraphic; }
|
||||
int currentTraceGraphic() const { return curTrace; }
|
||||
int graphicsCount() const { return graphics.size(); }
|
||||
Graphic::Buttons buttons() const { return buttons_; }
|
||||
Graphic::Alignment buttonsPosition() const { return align; }
|
||||
double historySize() const { return history; }
|
||||
double maxVisibleTime() const { return visible_time; }
|
||||
double autoXIncrement() const { return inc_x; }
|
||||
QRectF visualRect() const { return selrect; }
|
||||
QRectF defaultRect() const { return def_rect; }
|
||||
QRectF limit() const { return limit_; }
|
||||
QRect margins() const { return margins_; }
|
||||
int minimumRepaintInterval() const { return min_repaint_int; }
|
||||
double gridNumbersMultiplierX() const { return grid_numbers_x; }
|
||||
double gridNumbersMultiplierY() const { return grid_numbers_y; }
|
||||
Graduation graduationX() const { return grad_x; }
|
||||
Graduation graduationY() const { return grad_y; }
|
||||
double graduationStepX() const { return gridx; }
|
||||
double graduationStepY() const { return gridy; }
|
||||
AxisType axisType() const { return axis_type_x; }
|
||||
FloatingAxisType floatingAxisType() const { return floating_axis_type; }
|
||||
QVector<QPointF> graphicData() const { return graphics[curGraphic].polyline; }
|
||||
QVector<QPointF> graphicData(int index) const { return graphics[index].polyline; }
|
||||
GraphicsData graphicsData() const;
|
||||
QByteArray graphicsDataRaw() const;
|
||||
QWidget * viewport() const {return canvas;}
|
||||
QWidget * viewport() const { return canvas; }
|
||||
QByteArray save();
|
||||
void load(QByteArray ba);
|
||||
|
||||
GraphicType graphic(int arg) {if (arg < 0 || arg >= graphics.size()) return GraphicType(); return graphics[arg];}
|
||||
const QVector<GraphicType> & allGraphics() const {return graphics;}
|
||||
void setAllGraphics(const QVector<GraphicType> & g, bool update = true) {graphics = g; if (update) updateLegend();}
|
||||
GraphicType graphic(int arg) {
|
||||
if (arg < 0 || arg >= graphics.size()) return GraphicType();
|
||||
return graphics[arg];
|
||||
}
|
||||
const QVector<GraphicType> & allGraphics() const { return graphics; }
|
||||
void setAllGraphics(const QVector<GraphicType> & g, bool update = true) {
|
||||
graphics = g;
|
||||
if (update) updateLegend();
|
||||
}
|
||||
|
||||
double canvas2realX(double px) const;
|
||||
double canvas2realY(double py) const;
|
||||
double real2canvasX(double px) const;
|
||||
double real2canvasY(double py) const;
|
||||
QPointF canvas2real(QPointF canvas_point) const {return QPointF(canvas2realX(canvas_point.x()), canvas2realY(canvas_point.y()));}
|
||||
QPointF real2canvas(QPointF real_point) const {return QPointF(real2canvasX(real_point.x()), real2canvasY(real_point.y()));}
|
||||
QPointF canvas2real(QPointF canvas_point) const { return QPointF(canvas2realX(canvas_point.x()), canvas2realY(canvas_point.y())); }
|
||||
QPointF real2canvas(QPointF real_point) const { return QPointF(real2canvasX(real_point.x()), real2canvasY(real_point.y())); }
|
||||
QPolygonF real2canvas(const QPolygonF & real_polygon) const;
|
||||
QPolygonF canvas2real(const QPolygonF & canvas_polygon) const;
|
||||
double getScaleX() const {return real2canvasX(1.) - real2canvasX(0.);}
|
||||
double getScaleY() const {return real2canvasY(1.) - real2canvasY(0.);}
|
||||
QPointF getScale() const {return QPointF(getScaleX(), getScaleY());}
|
||||
double getScaleX() const { return real2canvasX(1.) - real2canvasX(0.); }
|
||||
double getScaleY() const { return real2canvasY(1.) - real2canvasY(0.); }
|
||||
QPointF getScale() const { return QPointF(getScaleX(), getScaleY()); }
|
||||
|
||||
public slots:
|
||||
void setCaption(const QString & str);
|
||||
void setLabelX(const QString & str) {label_x = str; hasLblX = (str.length() > 0); if (aupdate) update();}
|
||||
void setLabelY(const QString & str) {label_y = str; hasLblY = (str.length() > 0); if (aupdate) update();}
|
||||
void setGraphicName(const QString & str, int index) {graphics[index].name = str; updateLegend(); if (aupdate) update();}
|
||||
void setGraphicName(const QString & str) {graphics[curGraphic].name = str; updateLegend(); if (aupdate) update();}
|
||||
void setBackgroundColor(const QColor & color) {back_color = color; if (aupdate) update(); updateLegend();}
|
||||
void setTextColor(const QColor & color) {text_color = color; if (aupdate) update();}
|
||||
void setGraphicColor(const QColor & color, int index) {graphics[index].pen.setColor(color); updateLegend(); if (aupdate) update();}
|
||||
void setGraphicColor(const QColor & color) {setGraphicColor(color, curGraphic);}
|
||||
void setGridColor(const QColor & color) {grid_pen.setColor(color); if (aupdate) update();}
|
||||
void setSelectionColor(const QColor & color) {selpen.setColor(color);}
|
||||
void setGraphicStyle(const Qt::PenStyle & style, int index) {graphics[index].pen.setStyle(style); updateLegend(); if (aupdate) update();}
|
||||
void setGraphicStyle(const Qt::PenStyle & style) {setGraphicStyle(style, curGraphic);}
|
||||
void setGridStyle(const Qt::PenStyle & style) {grid_pen.setStyle(style); if (aupdate) update();}
|
||||
void setSelectionStyle(const Qt::PenStyle & style) {selpen.setStyle(style);}
|
||||
void setLabelX(const QString & str) {
|
||||
label_x = str;
|
||||
hasLblX = (str.length() > 0);
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setLabelY(const QString & str) {
|
||||
label_y = str;
|
||||
hasLblY = (str.length() > 0);
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicName(const QString & str, int index) {
|
||||
graphics[index].name = str;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicName(const QString & str) {
|
||||
graphics[curGraphic].name = str;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setBackgroundColor(const QColor & color) {
|
||||
back_color = color;
|
||||
if (aupdate) update();
|
||||
updateLegend();
|
||||
}
|
||||
void setTextColor(const QColor & color) {
|
||||
text_color = color;
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicColor(const QColor & color, int index) {
|
||||
graphics[index].pen.setColor(color);
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicColor(const QColor & color) { setGraphicColor(color, curGraphic); }
|
||||
void setGridColor(const QColor & color) {
|
||||
grid_pen.setColor(color);
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setSelectionColor(const QColor & color) { selpen.setColor(color); }
|
||||
void setGraphicStyle(const Qt::PenStyle & style, int index) {
|
||||
graphics[index].pen.setStyle(style);
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicStyle(const Qt::PenStyle & style) { setGraphicStyle(style, curGraphic); }
|
||||
void setGridStyle(const Qt::PenStyle & style) {
|
||||
grid_pen.setStyle(style);
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setSelectionStyle(const Qt::PenStyle & style) { selpen.setStyle(style); }
|
||||
void setGraphicVisible(bool visible, int index);
|
||||
void setGraphicVisible(bool visible) {setGraphicVisible(visible, curGraphic);}
|
||||
void setGraphicLineWidth(double w, int index) {if (qRound(w) == w) graphics[index].pen.setWidth(qRound(w)); else graphics[index].pen.setWidthF(w); updateLegend(); if (aupdate) update();}
|
||||
void setGraphicLineWidth(double w) {setGraphicLineWidth(w, curGraphic);}
|
||||
void setGraphicPointWidth(double w, int index) {graphics[index].pointWidth = w; updateLegend(); if (aupdate) update();}
|
||||
void setGraphicPointWidth(double w) {setGraphicPointWidth(w, curGraphic);}
|
||||
void setGraphicFillColor(const QColor & w, int index) {graphics[index].fill_color = w; updateLegend(); if (aupdate) update();}
|
||||
void setGraphicFillColor(const QColor & w) {setGraphicFillColor(w, curGraphic);}
|
||||
void setGraphicLinesEnabled(bool w, int index) {graphics[index].lines = w; updateLegend(); if (aupdate) update();}
|
||||
void setGraphicLinesEnabled(bool w) {setGraphicLinesEnabled(w, curGraphic);}
|
||||
void setGraphicPointsEnabled(bool w, int index) {graphics[index].points = w; updateLegend(); if (aupdate) update();}
|
||||
void setGraphicPointsEnabled(bool w) {setGraphicPointsEnabled(w, curGraphic);}
|
||||
void setGraphicFillEnabled(bool w, int index) {graphics[index].fill = w; updateLegend(); if (aupdate) update();}
|
||||
void setGraphicFillEnabled(bool w) {setGraphicFillEnabled(w, curGraphic);}
|
||||
void setGraphicPen(const QPen & pen, int index) {graphics[index].pen = pen; updateLegend(); if (aupdate) update();}
|
||||
void setGraphicPen(const QPen & pen) {setGraphicPen(pen, curGraphic);}
|
||||
void setGridPen(const QPen & pen) {grid_pen = pen; if (aupdate) update();}
|
||||
void setSelectionPen(const QPen & pen) {selpen = pen;}
|
||||
void setSelectionBrush(const QBrush & brush) {selbrush = brush;}
|
||||
void setNavigationEnabled(bool on) {navigation = on;}
|
||||
void setLODOptimization(bool yes) {m_LODOptimization = yes;}
|
||||
void setGraphicVisible(bool visible) { setGraphicVisible(visible, curGraphic); }
|
||||
void setGraphicLineWidth(double w, int index) {
|
||||
if (qRound(w) == w)
|
||||
graphics[index].pen.setWidth(qRound(w));
|
||||
else
|
||||
graphics[index].pen.setWidthF(w);
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicLineWidth(double w) { setGraphicLineWidth(w, curGraphic); }
|
||||
void setGraphicPointWidth(double w, int index) {
|
||||
graphics[index].pointWidth = w;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicPointWidth(double w) { setGraphicPointWidth(w, curGraphic); }
|
||||
void setGraphicFillColor(const QColor & w, int index) {
|
||||
graphics[index].fill_color = w;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicFillColor(const QColor & w) { setGraphicFillColor(w, curGraphic); }
|
||||
void setGraphicLinesEnabled(bool w, int index) {
|
||||
graphics[index].lines = w;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicLinesEnabled(bool w) { setGraphicLinesEnabled(w, curGraphic); }
|
||||
void setGraphicPointsEnabled(bool w, int index) {
|
||||
graphics[index].points = w;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicPointsEnabled(bool w) { setGraphicPointsEnabled(w, curGraphic); }
|
||||
void setGraphicFillEnabled(bool w, int index) {
|
||||
graphics[index].fill = w;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicFillEnabled(bool w) { setGraphicFillEnabled(w, curGraphic); }
|
||||
void setGraphicPen(const QPen & pen, int index) {
|
||||
graphics[index].pen = pen;
|
||||
updateLegend();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraphicPen(const QPen & pen) { setGraphicPen(pen, curGraphic); }
|
||||
void setGridPen(const QPen & pen) {
|
||||
grid_pen = pen;
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setSelectionPen(const QPen & pen) { selpen = pen; }
|
||||
void setSelectionBrush(const QBrush & brush) { selbrush = brush; }
|
||||
void setNavigationEnabled(bool on) { navigation = on; }
|
||||
void setLODOptimization(bool yes) { m_LODOptimization = yes; }
|
||||
void setOpenGL(bool on);
|
||||
void setAntialiasing(bool enabled);
|
||||
void setAutoUpdate(bool enabled) {aupdate = enabled;}
|
||||
void setAutoUpdate(bool enabled) { aupdate = enabled; }
|
||||
void setGridEnabled(bool enabled);
|
||||
void setBorderInputsVisible(bool visible);
|
||||
void setStatusVisible(bool visible);
|
||||
@@ -294,66 +392,149 @@ public slots:
|
||||
void setButtonsPosition(Graphic::Alignment a);
|
||||
void setHistorySize(double val);
|
||||
void setMaxVisibleTime(double val);
|
||||
void setAutoXIncrement(double val) {inc_x = val;}
|
||||
void setLimit(const QRectF & val) {limit_ = val;}
|
||||
void setMargins(const QRect & val) {margins_ = val; update();}
|
||||
void setMargins(int left_, int right_, int top_, int bottom_) {setMargins(QRect(left_, bottom_, right_, top_));}
|
||||
void setLeftMargin(int value) {margins_.moveLeft(value); setMargins(margins_);}
|
||||
void setRightMargin(int value) {margins_.setWidth(value); setMargins(margins_);}
|
||||
void setTopMargin(int value) {margins_.setHeight(value); setMargins(margins_);}
|
||||
void setBottomMargin(int value) {margins_.moveTop(value); setMargins(margins_);}
|
||||
void setMinimumRepaintInterval(const int & val) {min_repaint_int = val;}
|
||||
void setAutoXIncrement(double val) { inc_x = val; }
|
||||
void setLimit(const QRectF & val) { limit_ = val; }
|
||||
void setMargins(const QRect & val) {
|
||||
margins_ = val;
|
||||
update();
|
||||
}
|
||||
void setMargins(int left_, int right_, int top_, int bottom_) { setMargins(QRect(left_, bottom_, right_, top_)); }
|
||||
void setLeftMargin(int value) {
|
||||
margins_.moveLeft(value);
|
||||
setMargins(margins_);
|
||||
}
|
||||
void setRightMargin(int value) {
|
||||
margins_.setWidth(value);
|
||||
setMargins(margins_);
|
||||
}
|
||||
void setTopMargin(int value) {
|
||||
margins_.setHeight(value);
|
||||
setMargins(margins_);
|
||||
}
|
||||
void setBottomMargin(int value) {
|
||||
margins_.moveTop(value);
|
||||
setMargins(margins_);
|
||||
}
|
||||
void setMinimumRepaintInterval(const int & val) { min_repaint_int = val; }
|
||||
void setOnlyExpandY(bool yes);
|
||||
void setOnlyExpandX(bool yes);
|
||||
void setGesturesNavigation(bool yes);
|
||||
void setGraphicsData(const GraphicsData & gd);
|
||||
void setGraphicsDataRaw(const QByteArray & ba);
|
||||
|
||||
void setGridNumbersMultiplierX(double value) {grid_numbers_x = value; updateGraphics();}
|
||||
void setGridNumbersMultiplierY(double value) {grid_numbers_y = value; updateGraphics();}
|
||||
void setGraduationX(Graduation value) {grad_x = value; if (aupdate) update();;}
|
||||
void setGraduationY(Graduation value) {grad_y = value; if (aupdate) update();;}
|
||||
void setGraduationStepX(double sx) {gridx = sx; if (aupdate) update();}
|
||||
void setGraduationStepY(double sy) {gridy = sy; if (aupdate) update();}
|
||||
void setGraduationSteps(double sx, double sy) {gridx = sx; gridy = sy; if (aupdate) update();}
|
||||
void setAxisType(AxisType t) {axis_type_x = t; if (aupdate) update();}
|
||||
void setFloatingAxisType(FloatingAxisType t) {floating_axis_type = t; setGuidesCursor(); if (aupdate) update();}
|
||||
void setGridNumbersMultiplierX(double value) {
|
||||
grid_numbers_x = value;
|
||||
updateGraphics();
|
||||
}
|
||||
void setGridNumbersMultiplierY(double value) {
|
||||
grid_numbers_y = value;
|
||||
updateGraphics();
|
||||
}
|
||||
void setGraduationX(Graduation value) {
|
||||
grad_x = value;
|
||||
if (aupdate) update();
|
||||
;
|
||||
}
|
||||
void setGraduationY(Graduation value) {
|
||||
grad_y = value;
|
||||
if (aupdate) update();
|
||||
;
|
||||
}
|
||||
void setGraduationStepX(double sx) {
|
||||
gridx = sx;
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraduationStepY(double sy) {
|
||||
gridy = sy;
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setGraduationSteps(double sx, double sy) {
|
||||
gridx = sx;
|
||||
gridy = sy;
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setAxisType(AxisType t) {
|
||||
axis_type_x = t;
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setFloatingAxisType(FloatingAxisType t) {
|
||||
floating_axis_type = t;
|
||||
setGuidesCursor();
|
||||
if (aupdate) update();
|
||||
}
|
||||
void setFloatingAxisEnabled(bool on);
|
||||
|
||||
void addPoint(const QPointF & p, int graphic, bool update_ = true);
|
||||
void addPoint(const QPointF & p, bool update = true) {addPoint(p, curGraphic, update);}
|
||||
void addPoint(double x, double y, int graphic, bool update = true) {addPoint(QPointF(x, y), graphic, update);}
|
||||
void addPoint(double x, double y, bool update = true) {addPoint(QPointF(x, y), update);}
|
||||
void addPoint(double y, int graphic, bool update = true) {if (graphics[graphic].polyline.isEmpty()) addPoint(QPointF(0.0, y), graphic, update); else addPoint(QPointF(graphics[graphic].max_x + inc_x, y), graphic, update);}
|
||||
void addPoint(double y, bool update = true) {if (graphics[curGraphic].polyline.isEmpty()) addPoint(QPointF(0.0, y), update); else addPoint(QPointF(graphics[curGraphic].max_x + inc_x, y), update);}
|
||||
void addPoint(const QPointF & p, bool update = true) { addPoint(p, curGraphic, update); }
|
||||
void addPoint(double x, double y, int graphic, bool update = true) { addPoint(QPointF(x, y), graphic, update); }
|
||||
void addPoint(double x, double y, bool update = true) { addPoint(QPointF(x, y), update); }
|
||||
void addPoint(double y, int graphic, bool update = true) {
|
||||
if (graphics[graphic].polyline.isEmpty())
|
||||
addPoint(QPointF(0.0, y), graphic, update);
|
||||
else
|
||||
addPoint(QPointF(graphics[graphic].max_x + inc_x, y), graphic, update);
|
||||
}
|
||||
void addPoint(double y, bool update = true) {
|
||||
if (graphics[curGraphic].polyline.isEmpty())
|
||||
addPoint(QPointF(0.0, y), update);
|
||||
else
|
||||
addPoint(QPointF(graphics[curGraphic].max_x + inc_x, y), update);
|
||||
}
|
||||
void addPoints(const QPolygonF & pts, int graphic, bool update_ = true);
|
||||
void addPoints(const QPolygonF & pts, bool update = true) {addPoints(pts, curGraphic, update);}
|
||||
void addPoints(const QPolygonF & pts, bool update = true) { addPoints(pts, curGraphic, update); }
|
||||
void addPoints(const QVector<double> & pts, int graphic, bool update_ = true);
|
||||
void addPoints(const QVector<double> & pts, bool update = true) {addPoints(pts, curGraphic, update);}
|
||||
void addPoints(const QVector<double> & pts, bool update = true) { addPoints(pts, curGraphic, update); }
|
||||
void setGraphicData(const QVector<QPointF> & g, int graphic, bool update_ = true);
|
||||
void setGraphicData(const QVector<QPointF> & g) {setGraphicData(g, curGraphic);}
|
||||
void setGraphicProperties(const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true) {setGraphicProperties(curGraphic, name, color, style, width, visible);}
|
||||
void setGraphicProperties(int graphic, const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true);
|
||||
void addGraphic(const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true);
|
||||
void addGraphic(const GraphicType & gd, bool update = true) {graphics << gd; if (update) updateLegend();}
|
||||
void setGraphicData(const QVector<QPointF> & g) { setGraphicData(g, curGraphic); }
|
||||
void setGraphicProperties(const QString & name,
|
||||
const QColor & color = Qt::darkRed,
|
||||
Qt::PenStyle style = Qt::SolidLine,
|
||||
double width = 0.,
|
||||
bool visible = true) {
|
||||
setGraphicProperties(curGraphic, name, color, style, width, visible);
|
||||
}
|
||||
void setGraphicProperties(int graphic,
|
||||
const QString & name,
|
||||
const QColor & color = Qt::darkRed,
|
||||
Qt::PenStyle style = Qt::SolidLine,
|
||||
double width = 0.,
|
||||
bool visible = true);
|
||||
void addGraphic(const QString & name,
|
||||
const QColor & color = Qt::darkRed,
|
||||
Qt::PenStyle style = Qt::SolidLine,
|
||||
double width = 0.,
|
||||
bool visible = true);
|
||||
void addGraphic(const GraphicType & gd, bool update = true) {
|
||||
graphics << gd;
|
||||
if (update) updateLegend();
|
||||
}
|
||||
void setVisualRect(const QRectF & rect);
|
||||
void setDefaultRect(const QRectF & rect);
|
||||
void autofit() {on_graphic_buttonAutofit_clicked();}
|
||||
void autofit() { on_graphic_buttonAutofit_clicked(); }
|
||||
void saveImage(QString filename);
|
||||
void exportGraphics(QString filename, QChar decimal_point);
|
||||
void clear();
|
||||
void update(bool force);
|
||||
void update() {update(false);}
|
||||
void updateGraphics() {findGraphicsRect(); update();}
|
||||
void setCurrentGraphic(int arg) {if (arg < 0 || arg >= graphics.size()) return; curGraphic = arg;}
|
||||
void setTraceGraphic(int arg) {if (arg < 0 || arg >= graphics.size()) return; curTrace = arg;}
|
||||
void update() { update(false); }
|
||||
void updateGraphics() {
|
||||
findGraphicsRect();
|
||||
update();
|
||||
}
|
||||
void setCurrentGraphic(int arg) {
|
||||
if (arg < 0 || arg >= graphics.size()) return;
|
||||
curGraphic = arg;
|
||||
}
|
||||
void setTraceGraphic(int arg) {
|
||||
if (arg < 0 || arg >= graphics.size()) return;
|
||||
curTrace = arg;
|
||||
}
|
||||
void setGraphicsCount(int arg, bool update = true);
|
||||
void removeGraphic(int arg, bool update = true);
|
||||
void setCustomGridMarkFuncs(std::function<QString(double val)> fx, std::function<QString(double val)> fy);
|
||||
|
||||
void zoom(float factor);
|
||||
void zoomIn() {zoom(1. / 1.2);}
|
||||
void zoomOut() {zoom(1.2);}
|
||||
void zoomIn() { zoom(1. / 1.2); }
|
||||
void zoomOut() { zoom(1.2); }
|
||||
void fullscreen();
|
||||
|
||||
|
||||
@@ -365,9 +546,9 @@ protected:
|
||||
};
|
||||
|
||||
void changeEvent(QEvent * e) override;
|
||||
void resizeEvent(QResizeEvent * ) override;
|
||||
void showEvent(QShowEvent * ) override;
|
||||
QSize sizeHint() const override {return QSize(400, 300);}
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
void showEvent(QShowEvent *) override;
|
||||
QSize sizeHint() const override { return QSize(400, 300); }
|
||||
void timerEvent(QTimerEvent * e) override;
|
||||
bool eventFilter(QObject * o, QEvent * e) override;
|
||||
|
||||
@@ -379,7 +560,11 @@ protected:
|
||||
void findGraphicsRect(double start_x = 0., double end_x = 0., double start_y = 0., double end_y = 0.);
|
||||
void tick(int index, bool slide = true, bool update = true);
|
||||
void calcLOD(int index);
|
||||
void repaintCanvas(bool force = false) {if (tm.elapsed() < min_repaint_int && !force) return; tm.restart(); canvas->update();}
|
||||
void repaintCanvas(bool force = false) {
|
||||
if (tm.elapsed() < min_repaint_int && !force) return;
|
||||
tm.restart();
|
||||
canvas->update();
|
||||
}
|
||||
void drawGraphics();
|
||||
void drawGrid();
|
||||
void drawGuides();
|
||||
@@ -390,7 +575,7 @@ protected:
|
||||
void setCanvasCursor(QCursor cursor);
|
||||
void setGuidesCursor();
|
||||
void swapToBuffer();
|
||||
void swapToNormal() {bufferActive = false;}
|
||||
void swapToNormal() { bufferActive = false; }
|
||||
void setRectToLines();
|
||||
void checkLines();
|
||||
double splitRange(double range, int count = 1);
|
||||
@@ -398,7 +583,7 @@ protected:
|
||||
double roundTo(double value, double round_to);
|
||||
void roundDateTime(QDateTime & dt, int * c);
|
||||
void addDateTime(QDateTime & dt, int * c, qint64 mul = 1);
|
||||
QPointF absPoint(QPointF point) {return QPointF(qAbs(point.x()), qAbs(point.y()));}
|
||||
QPointF absPoint(QPointF point) { return QPointF(qAbs(point.x()), qAbs(point.y())); }
|
||||
QString pointCoords(QPointF point, bool x = true, bool y = true);
|
||||
QPair<QString, QString> gridMark(double v) const;
|
||||
void fillDateFormats();
|
||||
@@ -438,56 +623,76 @@ protected:
|
||||
double eminx, eminy, emaxx, emaxy, pause_phase, gesture_angle;
|
||||
int lastw, lasth, min_repaint_int, thick;
|
||||
int timer_pause, timer_record;
|
||||
bool aalias, aupdate, grid, guides, isFit, isOGL, isHover, bufferActive, cancel, pause_, gestures, m_LODOptimization, m_fakeGL, need_createGL;
|
||||
bool hasLblX, hasLblY, navigation, only_expand_y, only_expand_x, is_lines_update, leg_update, visible_update, fullscr, need_mouse_pan, was_trace;
|
||||
bool aalias, aupdate, grid, guides, isFit, isOGL, isHover, bufferActive, cancel, pause_, gestures, m_LODOptimization, m_fakeGL,
|
||||
need_createGL;
|
||||
bool hasLblX, hasLblY, navigation, only_expand_y, only_expand_x, is_lines_update, leg_update, visible_update, fullscr, need_mouse_pan,
|
||||
was_trace;
|
||||
std::function<QString(double val)> func_gridMarkX, func_gridMarkY;
|
||||
QVector<DateFormats> date_formats;
|
||||
QList<QImage> record_imgs;
|
||||
|
||||
protected slots:
|
||||
void canvasPaintEvent();
|
||||
void canvasMouseMoveEvent(QMouseEvent * );
|
||||
void canvasMousePressEvent(QMouseEvent * );
|
||||
void canvasMouseReleaseEvent(QMouseEvent * );
|
||||
void canvasMouseDoubleClickEvent(QMouseEvent * );
|
||||
void canvasWheelEvent(QWheelEvent * );
|
||||
void canvasLeaveEvent(QEvent * );
|
||||
void canvasKeyPressEvent(QKeyEvent * );
|
||||
void canvasMouseMoveEvent(QMouseEvent *);
|
||||
void canvasMousePressEvent(QMouseEvent *);
|
||||
void canvasMouseReleaseEvent(QMouseEvent *);
|
||||
void canvasMouseDoubleClickEvent(QMouseEvent *);
|
||||
void canvasWheelEvent(QWheelEvent *);
|
||||
void canvasLeaveEvent(QEvent *);
|
||||
void canvasKeyPressEvent(QKeyEvent *);
|
||||
void graphicVisibleChange(bool checked);
|
||||
void graphicAllVisibleChange(bool checked);
|
||||
void lineXMinChanged(double value) {selrect.setLeft(value); checkLines();}
|
||||
void lineXMaxChanged(double value) {selrect.setRight(value); checkLines();}
|
||||
void lineYMinChanged(double value) {selrect.setBottom(value); checkLines();}
|
||||
void lineYMaxChanged(double value) {selrect.setTop(value); checkLines();}
|
||||
void on_graphic_buttonClose_clicked() {emit closeRequest(this);}
|
||||
void on_graphic_buttonClear_clicked() {clear(); emit cleared();}
|
||||
void lineXMinChanged(double value) {
|
||||
selrect.setLeft(value);
|
||||
checkLines();
|
||||
}
|
||||
void lineXMaxChanged(double value) {
|
||||
selrect.setRight(value);
|
||||
checkLines();
|
||||
}
|
||||
void lineYMinChanged(double value) {
|
||||
selrect.setBottom(value);
|
||||
checkLines();
|
||||
}
|
||||
void lineYMaxChanged(double value) {
|
||||
selrect.setTop(value);
|
||||
checkLines();
|
||||
}
|
||||
void on_graphic_buttonClose_clicked() { emit closeRequest(this); }
|
||||
void on_graphic_buttonClear_clicked() {
|
||||
clear();
|
||||
emit cleared();
|
||||
}
|
||||
void on_graphic_buttonAutofit_clicked();
|
||||
void on_graphic_buttonConfigure_clicked();
|
||||
void on_graphic_buttonFullscreen_clicked() {fullscreen();}
|
||||
void on_graphic_buttonFullscreen_clicked() { fullscreen(); }
|
||||
void on_graphic_buttonSave_clicked();
|
||||
void on_graphic_buttonExport_clicked();
|
||||
void on_graphic_buttonRecord_clicked(bool checked);
|
||||
void on_graphic_checkGrid_toggled(bool checked) {grid = checked; update();}
|
||||
void on_graphic_checkGrid_toggled(bool checked) {
|
||||
grid = checked;
|
||||
update();
|
||||
}
|
||||
void on_graphic_checkGuides_toggled(bool checked);
|
||||
void on_graphic_actionExpandX_triggered(bool checked);
|
||||
void on_graphic_actionExpandY_triggered(bool checked);
|
||||
void on_graphic_checkBorderInputs_toggled(bool checked) {setBorderInputsVisible(checked);}
|
||||
void on_graphic_checkLegend_toggled(bool checked) {setLegendVisible(checked);}
|
||||
void on_graphic_checkPause_toggled(bool checked) {setPaused(checked);}
|
||||
void on_graphic_checkBorderInputs_toggled(bool checked) { setBorderInputsVisible(checked); }
|
||||
void on_graphic_checkLegend_toggled(bool checked) { setLegendVisible(checked); }
|
||||
void on_graphic_checkPause_toggled(bool checked) { setPaused(checked); }
|
||||
void actionGuidesTriggered(QAction * a);
|
||||
void enterFullscreen();
|
||||
void leaveFullscreen();
|
||||
void showMenu();
|
||||
|
||||
signals:
|
||||
void beforeGraphicPaintEvent(QPainter * );
|
||||
void graphicPaintEvent(QPainter * );
|
||||
void beforeGraphicPaintEvent(QPainter *);
|
||||
void graphicPaintEvent(QPainter *);
|
||||
void graphicMouseMoveEvent(QPointF point, int buttons);
|
||||
void graphicMousePressEvent(QPointF point, int buttons);
|
||||
void graphicMouseReleaseEvent(QPointF point, int buttons);
|
||||
void graphicWheelEvent(QPointF point, int delta);
|
||||
void graphicTraceEvent(int graphic, QPointF point);
|
||||
void closeRequest(QWidget * );
|
||||
void closeRequest(QWidget *);
|
||||
void cleared();
|
||||
void visualRectChanged();
|
||||
void graphicSettingsChanged();
|
||||
@@ -499,14 +704,20 @@ Q_DECLARE_METATYPE(Graphic::GraphicsData)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Graphic::Buttons)
|
||||
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const Graphic::Graduation & v) {s << (int)v; return s;}
|
||||
inline QDataStream & operator >>(QDataStream & s, Graphic::Graduation & v) {s >> *((int*)(&v)); return s;}
|
||||
inline QDataStream & operator<<(QDataStream & s, const Graphic::Graduation & v) {
|
||||
s << (int)v;
|
||||
return s;
|
||||
}
|
||||
inline QDataStream & operator>>(QDataStream & s, Graphic::Graduation & v) {
|
||||
s >> *((int *)(&v));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
class QAD_GRAPHIC_EXPORT __GraphicRegistrator__ {
|
||||
public:
|
||||
__GraphicRegistrator__() {
|
||||
qRegisterMetaType<QVector<QPointF> >("QVector<QPointF>");
|
||||
qRegisterMetaType<QVector<QPointF>>("QVector<QPointF>");
|
||||
qRegisterMetaType<Graphic::GraphicsData>("Graphic::GraphicsData");
|
||||
#if QT_VERSION_MAJOR <= 5
|
||||
qRegisterMetaTypeStreamOperators<Graphic::GraphicsData>("Graphic::GraphicsData");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "graphic_conf.h"
|
||||
|
||||
#include "qad_types.h"
|
||||
#include "ui_graphic_conf.h"
|
||||
|
||||
@@ -7,11 +8,10 @@ GraphicConf::GraphicConf(QVector<GraphicType> & graphics_, QWidget * parent): QD
|
||||
ui = new Ui::GraphicConf();
|
||||
ui->setupUi(this);
|
||||
QStringList styles;
|
||||
int fh = qMax<int>(fontMetrics().size(0, "0").height(), 22);
|
||||
int fh = qMax<int>(fontMetrics().size(0, "0").height(), 22);
|
||||
int thick = lineThickness(this);
|
||||
QSize sz(fh * 2.5, fh);
|
||||
styles << tr("NoPen") << tr("Solid") << tr("Dash")
|
||||
<< tr("Dot") << tr("Dash-Dot") << tr("Dash-Dot-Dot");
|
||||
styles << tr("NoPen") << tr("Solid") << tr("Dash") << tr("Dot") << tr("Dash-Dot") << tr("Dash-Dot-Dot");
|
||||
ui->comboStyleGrid->setIconSize(sz);
|
||||
ui->comboStyleGraphic->setIconSize(sz);
|
||||
ui->cbGraphicNames->setIconSize(sz);
|
||||
@@ -72,8 +72,10 @@ void GraphicConf::on_comboStyleGraphic_currentIndexChanged(int index) {
|
||||
|
||||
void GraphicConf::on_spinLineWidthGraphic_valueChanged(double value) {
|
||||
if (graphicItems.isEmpty()) return;
|
||||
if (qRound(value) == value) graphics[ui->cbGraphicNames->currentIndex()].pen.setWidth(qRound(value));
|
||||
else graphics[ui->cbGraphicNames->currentIndex()].pen.setWidthF(value);
|
||||
if (qRound(value) == value)
|
||||
graphics[ui->cbGraphicNames->currentIndex()].pen.setWidth(qRound(value));
|
||||
else
|
||||
graphics[ui->cbGraphicNames->currentIndex()].pen.setWidthF(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+44
-31
@@ -1,54 +1,61 @@
|
||||
/*
|
||||
QAD - Qt ADvanced
|
||||
QAD - Qt ADvanced
|
||||
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Lesser General Public License for more details.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHIC_CONF_H
|
||||
#define GRAPHIC_CONF_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QCheckBox>
|
||||
#include <QPen>
|
||||
#include <QPainter>
|
||||
#include "qad_graphic_export.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class GraphicConf;
|
||||
class GraphicConf;
|
||||
}
|
||||
|
||||
|
||||
struct QAD_GRAPHIC_EXPORT GraphicType {
|
||||
GraphicType(QString name_ = "y(x)", QColor color = Qt::red, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible_ = true) {
|
||||
GraphicType(QString name_ = "y(x)",
|
||||
QColor color = Qt::red,
|
||||
Qt::PenStyle style = Qt::SolidLine,
|
||||
double width = 0.,
|
||||
bool visible_ = true) {
|
||||
pen.setColor(color);
|
||||
pen.setStyle(style);
|
||||
lines = true;
|
||||
points = false;
|
||||
fill = false;
|
||||
lines = true;
|
||||
points = false;
|
||||
fill = false;
|
||||
fill_color = Qt::yellow;
|
||||
if (qRound(width) == width) pen.setWidth(qRound(width));
|
||||
else pen.setWidthF(width);
|
||||
if (qRound(width) == width)
|
||||
pen.setWidth(qRound(width));
|
||||
else
|
||||
pen.setWidthF(width);
|
||||
pen.setWidth(1);
|
||||
pen.setCosmetic(true);
|
||||
max_x = 0.;
|
||||
name = name_;
|
||||
visible = visible_;
|
||||
max_x = 0.;
|
||||
name = name_;
|
||||
visible = visible_;
|
||||
pointWidth = 2.;
|
||||
pb = new QCheckBox(name);
|
||||
pb = new QCheckBox(name);
|
||||
}
|
||||
//~GraphicType() {delete pb;}
|
||||
QString name;
|
||||
@@ -72,14 +79,20 @@ struct QAD_GRAPHIC_EXPORT GraphicType {
|
||||
};
|
||||
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const GraphicType & v) {s << v.name << v.pen << v.fill_color << v.lines << v.points << v.fill << v.pointWidth << v.visible; return s;}
|
||||
inline QDataStream & operator >>(QDataStream & s, GraphicType & v) {s >> v.name >> v.pen >> v.fill_color >> v.lines >> v.points >> v.fill >> v.pointWidth >> v.visible; return s;}
|
||||
inline QDataStream & operator<<(QDataStream & s, const GraphicType & v) {
|
||||
s << v.name << v.pen << v.fill_color << v.lines << v.points << v.fill << v.pointWidth << v.visible;
|
||||
return s;
|
||||
}
|
||||
inline QDataStream & operator>>(QDataStream & s, GraphicType & v) {
|
||||
s >> v.name >> v.pen >> v.fill_color >> v.lines >> v.points >> v.fill >> v.pointWidth >> v.visible;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
class QAD_GRAPHIC_EXPORT GraphicConf: public QDialog
|
||||
{
|
||||
class QAD_GRAPHIC_EXPORT GraphicConf: public QDialog {
|
||||
Q_OBJECT
|
||||
friend class Graphic;
|
||||
|
||||
public:
|
||||
explicit GraphicConf(QVector<GraphicType> & graphics_, QWidget * parent = 0);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "graphic.h"
|
||||
#include "graphicplugin.h"
|
||||
|
||||
#include "graphic.h"
|
||||
|
||||
#include <QtCore/QtPlugin>
|
||||
|
||||
|
||||
@@ -10,8 +12,7 @@ GraphicPlugin::GraphicPlugin(QObject * parent): QObject(parent) {
|
||||
|
||||
void GraphicPlugin::initialize(QDesignerFormEditorInterface * /* core */) {
|
||||
m_designer = true;
|
||||
if (m_initialized)
|
||||
return;
|
||||
if (m_initialized) return;
|
||||
|
||||
// Add extension registrations, etc. here
|
||||
|
||||
@@ -26,8 +27,7 @@ bool GraphicPlugin::isInitialized() const {
|
||||
|
||||
QWidget * GraphicPlugin::createWidget(QWidget * parent) {
|
||||
auto ret = new Graphic(parent);
|
||||
if (m_designer)
|
||||
ret->m_fakeGL = true;
|
||||
if (m_designer) ret->m_fakeGL = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ QIcon GraphicPlugin::icon() const {
|
||||
|
||||
|
||||
QString GraphicPlugin::toolTip() const {
|
||||
return QLatin1String("");//QLatin1String("Widget for display any math graphics with grid and navigation");
|
||||
return QLatin1String(""); // QLatin1String("Widget for display any math graphics with grid and navigation");
|
||||
}
|
||||
|
||||
|
||||
@@ -70,4 +70,3 @@ QString GraphicPlugin::domXml() const {
|
||||
QString GraphicPlugin::includeFile() const {
|
||||
return QLatin1String("graphic.h");
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
# include <QDesignerCustomWidgetInterface>
|
||||
#endif
|
||||
|
||||
class GraphicPlugin: public QObject, public QDesignerCustomWidgetInterface
|
||||
{
|
||||
class GraphicPlugin
|
||||
: public QObject
|
||||
, public QDesignerCustomWidgetInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QDesignerCustomWidgetInterface)
|
||||
|
||||
@@ -30,7 +31,6 @@ public:
|
||||
|
||||
private:
|
||||
bool m_initialized, m_designer;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "qad_graphic.h"
|
||||
|
||||
#include "graphicplugin.h"
|
||||
|
||||
QADGraphic::QADGraphic(QObject * parent): QObject(parent)
|
||||
{
|
||||
QADGraphic::QADGraphic(QObject * parent): QObject(parent) {
|
||||
m_widgets.append(new GraphicPlugin(this));
|
||||
}
|
||||
|
||||
|
||||
QList<QDesignerCustomWidgetInterface * > QADGraphic::customWidgets() const {
|
||||
QList<QDesignerCustomWidgetInterface *> QADGraphic::customWidgets() const {
|
||||
return m_widgets;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
#ifndef QAD_GRAPHIC_H
|
||||
#define QAD_GRAPHIC_H
|
||||
|
||||
#include <QtDesigner/QtDesigner>
|
||||
#include <QtCore/qplugin.h>
|
||||
#include <QtDesigner/QtDesigner>
|
||||
|
||||
class QADGraphic: public QObject, public QDesignerCustomWidgetCollectionInterface
|
||||
{
|
||||
class QADGraphic
|
||||
: public QObject
|
||||
, public QDesignerCustomWidgetCollectionInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
|
||||
#if QT_VERSION >= 0x050000
|
||||
Q_PLUGIN_METADATA(IID "qad.graphic")
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit QADGraphic(QObject * parent = 0);
|
||||
virtual QList<QDesignerCustomWidgetInterface * > customWidgets() const;
|
||||
virtual QList<QDesignerCustomWidgetInterface *> customWidgets() const;
|
||||
|
||||
private:
|
||||
QList<QDesignerCustomWidgetInterface * > m_widgets;
|
||||
|
||||
QList<QDesignerCustomWidgetInterface *> m_widgets;
|
||||
};
|
||||
|
||||
#endif // QAD_GRAPHIC_H
|
||||
|
||||
+15
-11
@@ -1,8 +1,8 @@
|
||||
#ifndef UGLWIDGET_H
|
||||
#define UGLWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDebug>
|
||||
#include <QWidget>
|
||||
#if QT_VERSION >= 0x050400
|
||||
# include <QOpenGLWidget>
|
||||
typedef QOpenGLWidget __GLWidget__;
|
||||
@@ -10,32 +10,37 @@ typedef QOpenGLWidget __GLWidget__;
|
||||
# include <QGLWidget>
|
||||
typedef QGLWidget __GLWidget__;
|
||||
# ifndef GL_MULTISAMPLE
|
||||
# define GL_MULTISAMPLE 0x809D
|
||||
# define GL_MULTISAMPLE 0x809D
|
||||
# endif
|
||||
#endif
|
||||
#include "qad_graphic_export.h"
|
||||
|
||||
|
||||
class QAD_GRAPHIC_EXPORT UGLWidget: public __GLWidget__
|
||||
{
|
||||
class QAD_GRAPHIC_EXPORT UGLWidget: public __GLWidget__ {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
#if QT_VERSION >= 0x050400
|
||||
UGLWidget(QWidget * parent = 0): __GLWidget__(parent) {QSurfaceFormat sf = format(); sf.setSamples(8); setFormat(sf);}
|
||||
UGLWidget(QWidget * parent = 0): __GLWidget__(parent) {
|
||||
QSurfaceFormat sf = format();
|
||||
sf.setSamples(8);
|
||||
setFormat(sf);
|
||||
}
|
||||
#else
|
||||
UGLWidget(QWidget * parent = 0): __GLWidget__(QGLFormat(QGL::DoubleBuffer | QGL::AlphaChannel | QGL::DirectRendering | QGL::SampleBuffers), parent) {}
|
||||
UGLWidget(QWidget * parent = 0)
|
||||
: __GLWidget__(QGLFormat(QGL::DoubleBuffer | QGL::AlphaChannel | QGL::DirectRendering | QGL::SampleBuffers), parent) {}
|
||||
#endif
|
||||
//UGLWidget(QGLContext * context, QWidget * parent = 0): __GLWidget__(context, parent) {}
|
||||
// UGLWidget(QGLContext * context, QWidget * parent = 0): __GLWidget__(context, parent) {}
|
||||
|
||||
#if QT_VERSION >= 0x050400
|
||||
QImage grabFrameBuffer() {return grabFramebuffer();}
|
||||
QImage grabFrameBuffer() { return grabFramebuffer(); }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#if QT_VERSION >= 0x050400
|
||||
virtual void paintGL() {emit paintSignal();}
|
||||
virtual void paintGL() { emit paintSignal(); }
|
||||
#else
|
||||
virtual void paintEvent(QPaintEvent * ) {emit paintSignal();}
|
||||
virtual void paintEvent(QPaintEvent *) { emit paintSignal(); }
|
||||
#endif
|
||||
virtual void resizeEvent(QResizeEvent * e) {
|
||||
__GLWidget__::resizeEvent(e);
|
||||
@@ -63,7 +68,6 @@ signals:
|
||||
void wheelEvent(QWheelEvent * e);
|
||||
void resizeSignal();
|
||||
void paintSignal();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
#ifndef UWIDGET_H
|
||||
#define UWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "qad_graphic_export.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QEvent>
|
||||
#include "qad_graphic_export.h"
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
class QAD_GRAPHIC_EXPORT UWidget: public QWidget
|
||||
{
|
||||
class QAD_GRAPHIC_EXPORT UWidget: public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UWidget(QWidget * parent = 0): QWidget(parent) {}
|
||||
|
||||
|
||||
private:
|
||||
virtual bool event(QEvent * e) {
|
||||
if (e->type() != QEvent::Paint) return QWidget::event(e);
|
||||
@@ -27,7 +28,7 @@ private:
|
||||
#endif
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
emit paintEvent((QPaintEvent * )e);
|
||||
emit paintEvent((QPaintEvent *)e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,7 +52,6 @@ signals:
|
||||
void showEvent(QShowEvent * e);
|
||||
void wheelEvent(QWheelEvent * e);
|
||||
void paintEvent(QPaintEvent * e);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user