diff --git a/README.md b/README.md index bd30ae4df..62a91a2bb 100644 --- a/README.md +++ b/README.md @@ -40,5 +40,5 @@ http://rawpedia.rawtherapee.com/Linux Windows: http://rawpedia.rawtherapee.com/Windows -OS X: +macOS: http://rawpedia.rawtherapee.com/macOS diff --git a/rtdata/dcpprofiles/NIKON D300.dcp b/rtdata/dcpprofiles/NIKON D300.dcp new file mode 100644 index 000000000..6aafdc616 Binary files /dev/null and b/rtdata/dcpprofiles/NIKON D300.dcp differ diff --git a/rtdata/dcpprofiles/NIKON D80.dcp b/rtdata/dcpprofiles/NIKON D80.dcp new file mode 100644 index 000000000..965c358aa Binary files /dev/null and b/rtdata/dcpprofiles/NIKON D80.dcp differ diff --git a/rtdata/dcpprofiles/NIKON D810.dcp b/rtdata/dcpprofiles/NIKON D810.dcp index 58f90c983..a946c1be2 100644 Binary files a/rtdata/dcpprofiles/NIKON D810.dcp and b/rtdata/dcpprofiles/NIKON D810.dcp differ diff --git a/rtdata/dcpprofiles/Nikon D300.dcp b/rtdata/dcpprofiles/Nikon D300.dcp deleted file mode 100644 index 3b1100b9d..000000000 Binary files a/rtdata/dcpprofiles/Nikon D300.dcp and /dev/null differ diff --git a/rtdata/dcpprofiles/OLYMPUS E-M1MarkII.dcp b/rtdata/dcpprofiles/OLYMPUS E-M1MarkII.dcp new file mode 100644 index 000000000..f32d01302 Binary files /dev/null and b/rtdata/dcpprofiles/OLYMPUS E-M1MarkII.dcp differ diff --git a/rtdata/dcpprofiles/Panasonic DMC-GX85.dcp b/rtdata/dcpprofiles/Panasonic DMC-GX85.dcp new file mode 100644 index 000000000..82d722a8c Binary files /dev/null and b/rtdata/dcpprofiles/Panasonic DMC-GX85.dcp differ diff --git a/rtdata/languages/default b/rtdata/languages/default index 8a52cf990..2a9ed318a 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -741,6 +741,7 @@ HISTORY_MSG_506;Local - Denoise HISTORY_MSG_507;Local - LH Curve HISTORY_MSG_508;Local - Enable super HISTORY_MSG_509;Local - CC curve +HISTORY_MSG_510;Local - curve method HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 8623d26cd..3b6d98133 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -11,6 +11,7 @@ /*RT*/#define DJGPP #include "opthelper.h" + /* dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net @@ -6264,6 +6265,7 @@ void CLASS apply_tiff() tile_width = tiff_ifd[i].tile_width; tile_length = tiff_ifd[i].tile_length; shutter = tiff_ifd[i].shutter; + raw_size = tiff_ifd[i].bytes; raw = i; } } @@ -9016,6 +9018,9 @@ canon_a5: if (filters == 9) FORC(36) ((char *)xtrans)[c] = xtrans_abs[(c/6+top_margin) % 6][(c+left_margin) % 6]; + if(filters == 9 && raw_height * raw_width * 2 != raw_size) { + xtransCompressed = true; + } } else if (!strcmp(model,"KD-400Z")) { height = 1712; width = 2312; @@ -9865,6 +9870,8 @@ struct tiff_hdr { char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; +#include "xtranscompressed.cc" + /* RT: Delete from here */ /*RT*/#undef SQR /*RT*/#undef MAX diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 0a68b02cc..1ea938cc7 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -89,8 +89,51 @@ protected: unsigned black, cblack[4102], maximum, mix_green, raw_color, zero_is_bad; unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; unsigned tile_width, tile_length, gpsdata[32], load_flags; + bool xtransCompressed = false; + struct xtrans_params + { + char *q_table; /* quantization table */ + int q_point[5]; /* quantization points */ + int max_bits; + int min_value; + int raw_bits; + int total_values; + int maxDiff; + ushort line_width; + }; + + struct int_pair { + int value1; + int value2; + }; + + enum _xt_lines + { + _R0=0,_R1,_R2,_R3,_R4, + _G0,_G1,_G2,_G3,_G4,_G5,_G6,_G7, + _B0,_B1,_B2,_B3,_B4, + _ltotal + }; + + struct xtrans_block { + int cur_bit; // current bit being read (from left to right) + int cur_pos; // current position in a buffer + INT64 cur_buf_offset; // offset of this buffer in a file + unsigned max_read_size; // Amount of data to be read + int cur_buf_size; // buffer size + uchar *cur_buf; // currently read block + IMFILE *input; + struct int_pair grad_even[3][41]; // tables of gradients + struct int_pair grad_odd[3][41]; + ushort *linealloc; + ushort *linebuf[_ltotal]; + }; + + int fuji_total_lines, fuji_total_blocks, fuji_block_width, fuji_bits; + ushort raw_height, raw_width, height, width, top_margin, left_margin; ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; + unsigned raw_size; ushort *raw_image; float * float_raw_image; ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; @@ -226,6 +269,25 @@ void adobe_copy_pixel (unsigned row, unsigned col, ushort **rp); void lossless_dng_load_raw(); void packed_dng_load_raw(); void deflate_dng_load_raw(); +void init_xtrans(struct xtrans_params* info); +void fuji_fill_buffer(struct xtrans_block *info); +void init_xtrans_block(struct xtrans_block* info, const struct xtrans_params *params, INT64 raw_offset, unsigned dsize); +void copy_line_to_xtrans(struct xtrans_block* info, int cur_line, int cur_block, int cur_block_width); +void fuji_zerobits(struct xtrans_block* info, int *count); +void fuji_read_code(struct xtrans_block* info, int *data, int bits_to_read); +int bitDiff(int value1, int value2); +int fuji_decode_sample_even(struct xtrans_block* info, const struct xtrans_params * params, ushort* line_buf, int pos, struct int_pair* grads); +int fuji_decode_sample_odd(struct xtrans_block* info, const struct xtrans_params * params, ushort* line_buf, int pos, struct int_pair* grads); +void fuji_decode_interpolation_even(int line_width, ushort* line_buf, int pos); +void xtrans_extend_generic(ushort *linebuf[_ltotal], int line_width, int start, int end); +void xtrans_extend_red(ushort *linebuf[_ltotal], int line_width); +void xtrans_extend_green(ushort *linebuf[_ltotal], int line_width); +void xtrans_extend_blue(ushort *linebuf[_ltotal], int line_width); +void xtrans_decode_block(struct xtrans_block* info, const struct xtrans_params *params, int cur_line); +void xtrans_decode_strip(const struct xtrans_params* info_common, int cur_block, INT64 raw_offset, unsigned dsize); +void xtrans_compressed_load_raw(); +void xtrans_decode_loop(const struct xtrans_params* common_info, int count, INT64* raw_block_offsets, unsigned *block_sizes); +void parse_xtrans_header(); void pentax_load_raw(); void nikon_load_raw(); int nikon_is_compressed(); diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 7cbd443ea..47fa302b8 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -28,7 +28,19 @@ #include //#include // "ceil" rounding -#define SKIPS(a,b) ((a) / (b) + ((a) % (b) > 0)) +//#define SKIPS(a,b) ((a) / (b) + ((a) % (b) > 0)) + +namespace +{ + +// "ceil" rounding +template +constexpr T skips (T a, T b) +{ + return a / b + static_cast (a % b); +} + +} namespace rtengine { @@ -37,8 +49,8 @@ extern const Settings* settings; Crop::Crop (ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow) : PipetteBuffer (editDataProvider), origCrop (nullptr), laboCrop (nullptr), labnCrop (nullptr), - cropImg (nullptr), cbuf_real (nullptr), shbuf_real (nullptr), cshmap (nullptr), transCrop (nullptr), cieCrop (nullptr), cbuffer (nullptr), shbuffer (nullptr), - updating (false), newUpdatePending (false), skip (10), padding (0), + cropImg (nullptr), cbuf_real (nullptr), shbuf_real (nullptr), cshmap (nullptr), transCrop (nullptr), cieCrop (nullptr), cbuffer (nullptr), shbuffer (nullptr), + updating (false), newUpdatePending (false), skip (10), cropx (0), cropy (0), cropw (-1), croph (-1), trafx (0), trafy (0), trafw (-1), trafh (-1), rqcropx (0), rqcropy (0), rqcropw (-1), rqcroph (-1), @@ -116,6 +128,12 @@ void Crop::setEditSubscriber (EditSubscriber* newSubscriber) // If oldSubscriber == NULL && newSubscriber != NULL && newSubscriber->getEditingType() == ET_PIPETTE-> the image will be allocated when necessary } +bool Crop::hasListener() +{ + MyMutex::MyLock cropLock (cropMutex); + return cropImageListener; +} + void Crop::update (int todo) { MyMutex::MyLock cropLock (cropMutex); @@ -690,7 +708,7 @@ void Crop::update (int todo) } if (needstransform) - parent->ipf.transform (baseCrop, transCrop, cropx / skip, cropy / skip, trafx / skip, trafy / skip, SKIPS (parent->fw, skip), SKIPS (parent->fh, skip), parent->getFullWidth(), parent->getFullHeight(), + parent->ipf.transform (baseCrop, transCrop, cropx / skip, cropy / skip, trafx / skip, trafy / skip, skips (parent->fw, skip), skips (parent->fh, skip), parent->getFullWidth(), parent->getFullHeight(), parent->imgsrc->getMetaData()->getFocalLen(), parent->imgsrc->getMetaData()->getFocalLen35mm(), parent->imgsrc->getMetaData()->getFocusDist(), parent->imgsrc->getRotateDegree(), false); else { @@ -721,7 +739,7 @@ void Crop::update (int todo) // blurmap for shadow & highlights if ((todo & M_BLURMAP) && params.sh.enabled) { - double radius = sqrt (double (SKIPS (parent->fw, skip) * SKIPS (parent->fw, skip) + SKIPS (parent->fh, skip) * SKIPS (parent->fh, skip))) / 2.0; + double radius = sqrt (double (skips (parent->fw, skip) * skips (parent->fw, skip) + skips (parent->fh, skip) * skips (parent->fh, skip))) / 2.0; double shradius = params.sh.radius; if (!params.sh.hq) { @@ -817,7 +835,8 @@ void Crop::update (int todo) if (needslocal ) { // if (tyty ) { //Glib::ustring datalab2 = parent->imgsrc->getFileName() + ".mip"; - Glib::ustring pop = options.getUserProfilePath() + "/"; + // Glib::ustring pop = options.getUserProfilePath() + "/"; + Glib::ustring pop = options.cacheBaseDir + "/mip/"; Glib::ustring datalab; @@ -1011,7 +1030,7 @@ void Crop::update (int todo) params.locallab.chromaref = parent->chromarefs[sp]; params.locallab.lumaref = parent->lumarefs[sp]; - parent->ipf.Lab_Local (1, sp, (float**)shbuffer, labnCrop, labnCrop, trafx / skip, trafy / skip, cropx / skip, cropy / skip, SKIPS (parent->fw, skip), SKIPS (parent->fh, skip), parent->fw, parent->fh, locutili, skip, locRETgainCurve, locallutili, lllocalcurve2, loclhCurve, cclocalcurve2, params.locallab.hueref, params.locallab.chromaref, params.locallab.lumaref); + parent->ipf.Lab_Local (1, sp, (float**)shbuffer, labnCrop, labnCrop, trafx / skip, trafy / skip, cropx / skip, cropy / skip, skips (parent->fw, skip), skips (parent->fh, skip), parent->fw, parent->fh, locutili, skip, locRETgainCurve, locallutili, lllocalcurve2, loclhCurve, cclocalcurve2, params.locallab.hueref, params.locallab.chromaref, params.locallab.lumaref); lllocalcurve2.clear(); cclocalcurve2.clear(); @@ -1247,7 +1266,7 @@ void Crop::update (int todo) params.locallab.chromaref = parent->chromarefs[sp]; params.locallab.lumaref = parent->lumarefs[sp]; - parent->ipf.Lab_Local (1, sp, (float**)shbuffer, labnCrop, labnCrop, trafx / skip, trafy / skip, cropx / skip, cropy / skip, SKIPS (parent->fw, skip), SKIPS (parent->fh, skip), parent->getFullWidth(), parent->getFullHeight(), locutili2, skip, locRETgainCurve, locallutili, lllocalcurve2, loclhCurve, cclocalcurve2, params.locallab.hueref, params.locallab.chromaref, params.locallab.lumaref); + parent->ipf.Lab_Local (1, sp, (float**)shbuffer, labnCrop, labnCrop, trafx / skip, trafy / skip, cropx / skip, cropy / skip, skips (parent->fw, skip), skips (parent->fh, skip), parent->getFullWidth(), parent->getFullHeight(), locutili2, skip, locRETgainCurve, locallutili, lllocalcurve2, loclhCurve, cclocalcurve2, params.locallab.hueref, params.locallab.chromaref, params.locallab.lumaref); lllocalcurve2.clear(); cclocalcurve2.clear(); @@ -1590,12 +1609,11 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte PreviewProps cp (orx, ory, orw, orh, skip); int orW, orH; parent->imgsrc->getSize (cp, orW, orH); + int cw = skips (bw, skip); + int ch = skips (bh, skip); - int cw = SKIPS (bw, skip); - int ch = SKIPS (bh, skip); - - leftBorder = SKIPS (rqx1 - bx1, skip); - upperBorder = SKIPS (rqy1 - by1, skip); + leftBorder = skips (rqx1 - bx1, skip); + upperBorder = skips (rqy1 - by1, skip); if (settings->verbose) { printf ("setsizes starts (%d, %d, %d, %d, %d, %d)\n", orW, orH, trafw, trafh, cw, ch); @@ -1787,5 +1805,22 @@ void Crop::fullUpdate () parent->updaterThreadStart.unlock (); } +int Crop::get_skip() +{ + MyMutex::MyLock lock (cropMutex); + return skip; } +int Crop::getLeftBorder() +{ + MyMutex::MyLock lock (cropMutex); + return leftBorder; +} + +int Crop::getUpperBorder() +{ + MyMutex::MyLock lock (cropMutex); + return upperBorder; +} + +} diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index c2fcc2a63..7fc165008 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -16,8 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#ifndef _CROP_H_ -#define _CROP_H_ +#pragma once #include "improccoordinator.h" #include "rtengine.h" @@ -59,19 +58,18 @@ protected: bool updating; /// Flag telling if an updater thread is currently processing bool newUpdatePending; /// Flag telling the updater thread that a new update is pending int skip; - int padding; /// Minimum space allowed around image in the display area int cropx, cropy, cropw, croph; /// size of the detail crop image ('skip' taken into account), with border int trafx, trafy, trafw, trafh; /// the size and position to get from the imagesource that is transformed to the requested crop area int rqcropx, rqcropy, rqcropw, rqcroph; /// size of the requested detail crop image (the image might be smaller) (without border) - int borderRequested; /// requested extra border size for image processing + const int borderRequested; /// requested extra border size for image processing int upperBorder, leftBorder; /// extra border size really allocated for image processing bool cropAllocated; DetailedCropListener* cropImageListener; MyMutex cropMutex; - ImProcCoordinator* parent; - bool isDetailWindow; + ImProcCoordinator* const parent; + const bool isDetailWindow; EditUniqueID getCurrEditID(); bool setCropSizes (int cropX, int cropY, int cropW, int cropH, int skip, bool internal); void freeAll (); @@ -80,20 +78,8 @@ public: Crop (ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow); virtual ~Crop (); // MyMutex* locMutex; - - void mLock () - { - cropMutex.lock(); - } - void mUnlock () - { - cropMutex.lock(); - } void setEditSubscriber (EditSubscriber* newSubscriber); - bool hasListener () - { - return cropImageListener; - } + bool hasListener(); void update (int todo); void setWindow (int cropX, int cropY, int cropW, int cropH, int skip) { @@ -109,22 +95,8 @@ public: void setListener (DetailedCropListener* il); void destroy (); - int get_skip () - { - return skip; - } - int getPadding () - { - return padding; - } - int getLeftBorder () - { - return leftBorder; - } - int getUpperBorder () - { - return upperBorder; - } + int get_skip(); + int getLeftBorder(); + int getUpperBorder(); }; } -#endif diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 48342087b..a32e574d9 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -739,7 +739,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } // printf("mip file=%s \n", datalab.c_str()); - Glib::ustring pop = options.getUserProfilePath() + "/"; + // Glib::ustring pop = options.getUserProfilePath() + "/"; + Glib::ustring pop = options.cacheBaseDir + "/mip/"; + Glib::ustring datal; diff --git a/rtengine/opthelper.h b/rtengine/opthelper.h index bee97f6b2..4b34fc58f 100644 --- a/rtengine/opthelper.h +++ b/rtengine/opthelper.h @@ -69,7 +69,7 @@ #define ALIGNED64 #define ALIGNED16 #endif - #if !defined(__clang__) && defined _OPENMP + #if defined _OPENMP #define _RT_NESTED_OPENMP #endif #endif diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index dc91da64d..bfe7092f2 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -435,6 +435,10 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene return 2; } + if(xtransCompressed) { + parse_xtrans_header(); + } + if (flip == 5) { this->rotate_deg = 270; } else if (flip == 3) { diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 0e61c8086..da6f139b6 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -949,7 +949,9 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p //Glib::ustring datalab = imgsrc->getFileName() + ".mip"; - Glib::ustring pop = options.getUserProfilePath() + "/"; + // Glib::ustring pop = options.getUserProfilePath() + "/"; + Glib::ustring pop = options.cacheBaseDir + "/mip/"; + Glib::ustring datalab; if (options.mip == MI_opt) { diff --git a/rtengine/xtranscompressed.cc b/rtengine/xtranscompressed.cc new file mode 100644 index 000000000..854ffec2f --- /dev/null +++ b/rtengine/xtranscompressed.cc @@ -0,0 +1,800 @@ +/* -*- C++ -*- + * File: xtranscompressed.cpp + * Copyright (C) 2016 Alexey Danilchenko + * + * Adopted to LibRaw by Alex Tutubalin, lexa@lexa.ru + * LibRaw Fujifilm/compressed decoder + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of three licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + * Adopted to RawTherapee by Ingo Weyrich + + */ + +void CLASS init_xtrans (struct xtrans_params* info) +{ + int cur_val, i; + char *qt; + + if (fuji_block_width % 3) { + derror(); + } + + info->q_table = (char *) malloc (32768); + merror (info->q_table, "init_xtrans()"); + + info->line_width = (fuji_block_width * 2) / 3; + + info->q_point[0] = 0; + info->q_point[1] = 0x12; + info->q_point[2] = 0x43; + info->q_point[3] = 0x114; + info->q_point[4] = (1 << fuji_bits) - 1; + info->min_value = 0x40; + + cur_val = -info->q_point[4]; + + for (qt = info->q_table; cur_val <= info->q_point[4]; ++qt, ++cur_val) { + if (cur_val <= -info->q_point[3]) { + *qt = -4; + } else if (cur_val <= -info->q_point[2]) { + *qt = -3; + } else if (cur_val <= -info->q_point[1]) { + *qt = -2; + } else if (cur_val < 0) { + *qt = -1; + } else if (cur_val == 0) { + *qt = 0; + } else if (cur_val < info->q_point[1]) { + *qt = 1; + } else if (cur_val < info->q_point[2]) { + *qt = 2; + } else if (cur_val < info->q_point[3]) { + *qt = 3; + } else { + *qt = 4; + } + } + + // populting gradients + if (info->q_point[4] == 0x3FFF) { + info->total_values = 0x4000; + info->raw_bits = 14; + info->max_bits = 56; + info->maxDiff = 256; + } else if (info->q_point[4] == 0xFFF) { + info->total_values = 4096; + info->raw_bits = 12; + info->max_bits = 48; + info->maxDiff = 64; + } else { + derror(); + } +} + +#define XTRANS_BUF_SIZE 0x10000u + +void CLASS fuji_fill_buffer (struct xtrans_block *info) +{ + if (info->cur_pos >= info->cur_buf_size) { + info->cur_pos = 0; + info->cur_buf_offset += info->cur_buf_size; +#ifdef _OPENMP + #pragma omp critical +#endif + { + fseek (info->input, info->cur_buf_offset, SEEK_SET); + info->cur_buf_size = fread (info->cur_buf, 1, std::min (info->max_read_size, XTRANS_BUF_SIZE), info->input); + } + if (info->cur_buf_size < 1) // nothing read + ;//throw LIBRAW_EXCEPTION_IO_EOF; + + info->max_read_size -= info->cur_buf_size; + } +} + +void CLASS init_xtrans_block (struct xtrans_block* info, const struct xtrans_params *params, INT64 raw_offset, unsigned dsize) +{ + info->linealloc = (ushort*)calloc (sizeof (ushort), _ltotal * (params->line_width + 2)); + merror (info->linealloc, "init_xtrans_block()"); + + info->input = ifp; + INT64 fsize = info->input->size; + info->max_read_size = std::min (unsigned (fsize - raw_offset), dsize + 16); // Data size may be incorrect? + + info->linebuf[_R0] = info->linealloc; + + for (int i = _R1; i <= _B4; i++) { + info->linebuf[i] = info->linebuf[i - 1] + params->line_width + 2; + } + + // init buffer + info->cur_buf = (uchar*)malloc (XTRANS_BUF_SIZE); + merror (info->cur_buf, "init_xtrans_block()"); + info->cur_bit = 0; + info->cur_pos = 0; + info->cur_buf_offset = raw_offset; + + for (int j = 0; j < 3; j++) + for (int i = 0; i < 41; i++) { + info->grad_even[j][i].value1 = params->maxDiff; + info->grad_even[j][i].value2 = 1; + info->grad_odd[j][i].value1 = params->maxDiff; + info->grad_odd[j][i].value2 = 1; + } + + info->cur_buf_size = 0; + fuji_fill_buffer (info); +} + +void CLASS copy_line_to_xtrans (struct xtrans_block* info, int cur_line, int cur_block, int cur_block_width) +{ + ushort *lineBufB[3]; + ushort *lineBufG[6]; + ushort *lineBufR[3]; + unsigned pixel_count; + ushort* line_buf; + int index; + + int offset = fuji_block_width * cur_block + 6 * raw_width * cur_line; + ushort* raw_block_data = raw_image + offset; + int row_count = 0; + + for (int i = 0; i < 3; i++) { + lineBufR[i] = info->linebuf[_R2 + i] + 1; + lineBufB[i] = info->linebuf[_B2 + i] + 1; + } + + for (int i = 0; i < 6; i++) { + lineBufG[i] = info->linebuf[_G2 + i] + 1; + } + + while (row_count < 6) { + pixel_count = 0; + + while (pixel_count < cur_block_width) { + switch (xtrans_abs[row_count][ (pixel_count % 6)]) { + case 0: // red + line_buf = lineBufR[row_count >> 1]; + break; + + case 1: // green + line_buf = lineBufG[row_count]; + break; + + case 2: // blue + line_buf = lineBufB[row_count >> 1]; + break; + } + + index = (((pixel_count * 2 / 3) & 0x7FFFFFFE) | (pixel_count % 3) & 1) + ((pixel_count % 3) >> 1); + raw_block_data[pixel_count] = line_buf[index]; + + ++pixel_count; + } + + ++row_count; + raw_block_data += raw_width; + } +} + +#define fuji_quant_gradient(i,v1,v2) (9*i->q_table[i->q_point[4]+(v1)] + i->q_table[i->q_point[4]+(v2)]) + +void CLASS fuji_zerobits (struct xtrans_block* info, int *count) +{ + uchar zero = 0; + *count = 0; + + while (zero == 0) { + zero = (info->cur_buf[info->cur_pos] >> (7 - info->cur_bit)) & 1; + info->cur_bit++; + info->cur_bit &= 7; + + if (!info->cur_bit) { + ++info->cur_pos; + fuji_fill_buffer (info); + } + + if (zero) { + break; + } + + ++*count; + } +} + +void CLASS fuji_read_code (struct xtrans_block* info, int *data, int bits_to_read) +{ + uchar bits_left = bits_to_read; + uchar bits_left_in_byte = 8 - (info->cur_bit & 7); + *data = 0; + + if (!bits_to_read) { + return; + } + + if (bits_to_read >= bits_left_in_byte) { + do { + *data <<= bits_left_in_byte; + bits_left -= bits_left_in_byte; + *data |= info->cur_buf[info->cur_pos] & ((1 << bits_left_in_byte) - 1); + ++info->cur_pos; + fuji_fill_buffer (info); + bits_left_in_byte = 8; + } while (bits_left >= 8); + } + + if (!bits_left) { + info->cur_bit = (8 - (bits_left_in_byte & 7)) & 7; + return; + } + + *data <<= bits_left; + bits_left_in_byte -= bits_left; + *data |= ((1 << bits_left) - 1) & ((unsigned)info->cur_buf[info->cur_pos] >> bits_left_in_byte); + info->cur_bit = (8 - (bits_left_in_byte & 7)) & 7; +} + +int CLASS bitDiff (int value1, int value2) +{ + int decBits = 0; + + if ( value2 < value1 ) + while (decBits <= 12 && (value2 << ++decBits) < value1) + ; + + return decBits; +} + +int CLASS fuji_decode_sample_even (struct xtrans_block* info, const struct xtrans_params * params, ushort* line_buf, int pos, struct int_pair* grads) +{ + int interp_val = 0; + int errcnt = 0; + + int sample = 0, code = 0; + ushort* line_buf_cur = line_buf + pos; + int Rb = line_buf_cur[-2 - params->line_width]; + int Rc = line_buf_cur[-3 - params->line_width]; + int Rd = line_buf_cur[-1 - params->line_width]; + int Rf = line_buf_cur[-4 - 2 * params->line_width]; + + int grad, gradient, diffRcRb, diffRfRb, diffRdRb; + + grad = fuji_quant_gradient (params, Rb - Rf, Rc - Rb); + gradient = std::abs (grad); + diffRcRb = std::abs (Rc - Rb); + diffRfRb = std::abs (Rf - Rb); + diffRdRb = std::abs (Rd - Rb); + + if ( diffRcRb > diffRfRb && diffRcRb > diffRdRb ) { + interp_val = Rf + Rd + 2 * Rb; + } else if ( diffRdRb > diffRcRb && diffRdRb > diffRfRb ) { + interp_val = Rf + Rc + 2 * Rb; + } else { + interp_val = Rd + Rc + 2 * Rb; + } + + + fuji_zerobits (info, &sample); + + if (sample < params->max_bits - params->raw_bits - 1) { + int decBits = bitDiff (grads[gradient].value1, grads[gradient].value2); + fuji_read_code (info, &code, decBits); + code += sample << decBits; + } else { + fuji_read_code (info, &code, params->raw_bits); + code++; + } + + if (code < 0 || code >= params->total_values) { + errcnt++; + } + + if (code & 1) { + code = -1 - code / 2; + } else { + code /= 2; + } + + grads[gradient].value1 += std::abs (code); + + if (grads[gradient].value2 == params->min_value ) { + grads[gradient].value1 >>= 1; + grads[gradient].value2 >>= 1; + } + + grads[gradient].value2++; + + if (grad < 0) { + interp_val = (interp_val >> 2) - code; + } else { + interp_val = (interp_val >> 2) + code; + } + + if ( interp_val < 0 ) { + interp_val += params->total_values; + } else if (interp_val > params->q_point[4]) { + interp_val -= params->total_values; + } + + if ( interp_val >= 0 ) { + line_buf_cur[0] = std::min (interp_val, params->q_point[4]); + } else { + line_buf_cur[0] = 0; + } + + return errcnt; +} + +int CLASS fuji_decode_sample_odd (struct xtrans_block* info, const struct xtrans_params * params, ushort* line_buf, int pos, struct int_pair* grads) +{ + int interp_val = 0; + int errcnt = 0; + + int sample = 0, code = 0; + ushort* line_buf_cur = line_buf + pos; + int Ra = line_buf_cur[-1]; + int Rb = line_buf_cur[-2 - params->line_width]; + int Rc = line_buf_cur[-3 - params->line_width]; + int Rd = line_buf_cur[-1 - params->line_width]; + int Rg = line_buf_cur[1]; + + int grad, gradient; + + grad = fuji_quant_gradient (params, Rb - Rc, Rc - Ra); + gradient = std::abs (grad); + + if ((Rb > Rc && Rb > Rd) || (Rb < Rc && Rb < Rd)) { + interp_val = (Rg + Ra + 2 * Rb) >> 2; + } else { + interp_val = (Ra + Rg) >> 1; + } + + fuji_zerobits (info, &sample); + + if (sample < params->max_bits - params->raw_bits - 1) { + int decBits = bitDiff (grads[gradient].value1, grads[gradient].value2); + fuji_read_code (info, &code, decBits); + code += sample << decBits; + } else { + fuji_read_code (info, &code, params->raw_bits); + code++; + } + + if (code < 0 || code >= params->total_values) { + errcnt++; + } + + if (code & 1) { + code = -1 - code / 2; + } else { + code /= 2; + } + + grads[gradient].value1 += std::abs (code); + + if (grads[gradient].value2 == params->min_value) { + grads[gradient].value1 >>= 1; + grads[gradient].value2 >>= 1; + } + + grads[gradient].value2++; + + if (grad < 0) { + interp_val -= code; + } else { + interp_val += code; + } + + if ( interp_val < 0 ) { + interp_val += params->total_values; + } else if (interp_val > params->q_point[4]) { + interp_val -= params->total_values; + } + + if ( interp_val >= 0 ) { + line_buf_cur[0] = std::min(interp_val, params->q_point[4]); + } else { + line_buf_cur[0] = 0; + } + + return errcnt; +} + +void CLASS fuji_decode_interpolation_even (int line_width, ushort* line_buf, int pos) +{ + ushort* line_buf_cur = line_buf + pos; + int Rb = line_buf_cur[-2 - line_width]; + int Rc = line_buf_cur[-3 - line_width]; + int Rd = line_buf_cur[-1 - line_width]; + int Rf = line_buf_cur[-4 - 2 * line_width]; + int diffRcRb = std::abs (Rc - Rb); + int diffRfRb = std::abs (Rf - Rb); + int diffRdRb = std::abs (Rd - Rb); + + if ( diffRcRb > diffRfRb && diffRcRb > diffRdRb ) { + *line_buf_cur = (Rf + Rd + 2 * Rb) >> 2; + } else if ( diffRdRb > diffRcRb && diffRdRb > diffRfRb ) { + *line_buf_cur = (Rf + Rc + 2 * Rb) >> 2; + } else { + *line_buf_cur = (Rd + Rc + 2 * Rb) >> 2; + } +} + +void CLASS xtrans_extend_generic (ushort *linebuf[_ltotal], int line_width, int start, int end) +{ + for (int i = start; i <= end; i++) { + linebuf[i][0] = linebuf[i - 1][1]; + linebuf[i][line_width + 1] = linebuf[i - 1][line_width]; + } +} + +void CLASS xtrans_extend_red (ushort *linebuf[_ltotal], int line_width) +{ + xtrans_extend_generic (linebuf, line_width, _R2, _R4); +} + +void CLASS xtrans_extend_green (ushort *linebuf[_ltotal], int line_width) +{ + xtrans_extend_generic (linebuf, line_width, _G2, _G7); +} + +void CLASS xtrans_extend_blue (ushort *linebuf[_ltotal], int line_width) +{ + xtrans_extend_generic (linebuf, line_width, _B2, _B4); +} + +void CLASS xtrans_decode_block (struct xtrans_block* info, const struct xtrans_params *params, int cur_line) +{ + int r_even_pos = 0, r_odd_pos = 1; + int g_even_pos = 0, g_odd_pos = 1; + int b_even_pos = 0, b_odd_pos = 1; + + int errcnt = 0; + + const int line_width = params->line_width; + + while (g_even_pos < line_width || g_odd_pos < line_width) { + if (g_even_pos < line_width) { + fuji_decode_interpolation_even (line_width, info->linebuf[_R2] + 1, r_even_pos); + r_even_pos += 2; + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_G2] + 1, g_even_pos, info->grad_even[0]); + g_even_pos += 2; + } + + if (g_even_pos > 8) { + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_R2] + 1, r_odd_pos, info->grad_odd[0]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_G2] + 1, g_odd_pos, info->grad_odd[0]); + g_odd_pos += 2; + } + } + + xtrans_extend_red (info->linebuf, line_width); + xtrans_extend_green (info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) { + if (g_even_pos < line_width) { + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_G3] + 1, g_even_pos, info->grad_even[1]); + g_even_pos += 2; + fuji_decode_interpolation_even (line_width, info->linebuf[_B2] + 1, b_even_pos); + b_even_pos += 2; + } + + if (g_even_pos > 8) { + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_G3] + 1, g_odd_pos, info->grad_odd[1]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_B2] + 1, b_odd_pos, info->grad_odd[1]); + b_odd_pos += 2; + } + } + + xtrans_extend_green (info->linebuf, line_width); + xtrans_extend_blue (info->linebuf, line_width); + + r_even_pos = 0, r_odd_pos = 1; + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) { + if (g_even_pos < line_width) { + if (r_even_pos & 3) { + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_R3] + 1, r_even_pos, info->grad_even[2]); + } else { + fuji_decode_interpolation_even (line_width, info->linebuf[_R3] + 1, r_even_pos); + } + + r_even_pos += 2; + fuji_decode_interpolation_even (line_width, info->linebuf[_G4] + 1, g_even_pos); + g_even_pos += 2; + } + + if (g_even_pos > 8) { + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_R3] + 1, r_odd_pos, info->grad_odd[2]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_G4] + 1, g_odd_pos, info->grad_odd[2]); + g_odd_pos += 2; + } + } + + xtrans_extend_red (info->linebuf, line_width); + xtrans_extend_green (info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + b_even_pos = 0, b_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) { + if (g_even_pos < line_width) { + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_G5] + 1, g_even_pos, info->grad_even[0]); + g_even_pos += 2; + + if ((b_even_pos & 3) == 2) { + fuji_decode_interpolation_even (line_width, info->linebuf[_B3] + 1, b_even_pos); + } else { + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_B3] + 1, b_even_pos, info->grad_even[0]); + } + + b_even_pos += 2; + } + + if (g_even_pos > 8) { + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_G5] + 1, g_odd_pos, info->grad_odd[0]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_B3] + 1, b_odd_pos, info->grad_odd[0]); + b_odd_pos += 2; + } + } + + xtrans_extend_green (info->linebuf, line_width); + xtrans_extend_blue (info->linebuf, line_width); + + r_even_pos = 0, r_odd_pos = 1; + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) { + if (g_even_pos < line_width) { + if ((r_even_pos & 3) == 2) { + fuji_decode_interpolation_even (line_width, info->linebuf[_R4] + 1, r_even_pos); + } else { + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_R4] + 1, r_even_pos, info->grad_even[1]); + } + + r_even_pos += 2; + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_G6] + 1, g_even_pos, info->grad_even[1]); + g_even_pos += 2; + } + + if (g_even_pos > 8) { + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_R4] + 1, r_odd_pos, info->grad_odd[1]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_G6] + 1, g_odd_pos, info->grad_odd[1]); + g_odd_pos += 2; + } + } + + xtrans_extend_red (info->linebuf, line_width); + xtrans_extend_green (info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + b_even_pos = 0, b_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) { + if (g_even_pos < line_width) { + fuji_decode_interpolation_even (line_width, info->linebuf[_G7] + 1, g_even_pos); + g_even_pos += 2; + + if (b_even_pos & 3) { + errcnt += fuji_decode_sample_even (info, params, info->linebuf[_B4] + 1, b_even_pos, info->grad_even[2]); + } else { + fuji_decode_interpolation_even (line_width, info->linebuf[_B4] + 1, b_even_pos); + } + + b_even_pos += 2; + } + + if (g_even_pos > 8) { + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_G7] + 1, g_odd_pos, info->grad_odd[2]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd (info, params, info->linebuf[_B4] + 1, b_odd_pos, info->grad_odd[2]); + b_odd_pos += 2; + } + } + + xtrans_extend_green (info->linebuf, line_width); + xtrans_extend_blue (info->linebuf, line_width); + + if (errcnt) { + derror(); + } +} + +void CLASS xtrans_decode_strip (const struct xtrans_params* info_common, int cur_block, INT64 raw_offset, unsigned dsize) +{ + int cur_block_width, cur_line; + unsigned line_size; + struct xtrans_block info; + + init_xtrans_block (&info, info_common, raw_offset, dsize); + line_size = sizeof (ushort) * (info_common->line_width + 2); + + cur_block_width = fuji_block_width; + + if (cur_block + 1 == fuji_total_blocks) { + cur_block_width = raw_width % fuji_block_width; + } + + struct i_pair { + int a, b; + }; + + const i_pair mtable[6] = { {_R0, _R3}, {_R1, _R4}, {_G0, _G6}, {_G1, _G7}, {_B0, _B3}, {_B1, _B4}}, + ztable[3] = {{_R2, 3}, {_G2, 6}, {_B2, 3}}; + + for (cur_line = 0; cur_line < fuji_total_lines; cur_line++) { + xtrans_decode_block (&info, info_common, cur_line); + + // copy data from line buffers and advance + for (int i = 0; i < 6; i++) { + memcpy (info.linebuf[mtable[i].a], info.linebuf[mtable[i].b], line_size); + } + + copy_line_to_xtrans (&info, cur_line, cur_block, cur_block_width); + + for (int i = 0; i < 3; i++) { + memset (info.linebuf[ztable[i].a], 0, ztable[i].b * line_size); + info.linebuf[ztable[i].a][0] = info.linebuf[ztable[i].a - 1][1]; + info.linebuf[ztable[i].a][info_common->line_width + 1] = info.linebuf[ztable[i].a - 1][info_common->line_width]; + } + } + + // release data + free (info.linealloc); + free (info.cur_buf); +} + +static unsigned sgetn (int n, uchar *s) +{ + unsigned result = 0; + + while (n-- > 0) { + result = (result << 8) | (*s++); + } + + return result; +} + +void CLASS xtrans_compressed_load_raw() +{ + struct xtrans_params common_info; + int cur_block; + unsigned line_size, *block_sizes; + INT64 raw_offset, *raw_block_offsets; + //struct xtrans_block info; + + init_xtrans (&common_info); + line_size = sizeof (ushort) * (common_info.line_width + 2); + + // read block sizes + block_sizes = (unsigned*) malloc (sizeof (unsigned) * fuji_total_blocks); + merror (block_sizes, "xtrans_load_raw()"); + raw_block_offsets = (INT64*) malloc (sizeof (INT64) * fuji_total_blocks); + merror (raw_block_offsets, "xtrans_load_raw()"); + + raw_offset = sizeof (unsigned) * fuji_total_blocks; + + if (raw_offset & 0xC) { + raw_offset += 0x10 - (raw_offset & 0xC); + } + + raw_offset += data_offset; + + fseek (ifp, data_offset, SEEK_SET); + fread (block_sizes, 1, sizeof (unsigned)*fuji_total_blocks, ifp); + + raw_block_offsets[0] = raw_offset; + + // calculating raw block offsets + for (cur_block = 0; cur_block < fuji_total_blocks; cur_block++) { + unsigned bsize = sgetn (4, (uchar *) (block_sizes + cur_block)); + block_sizes[cur_block] = bsize; + } + + for (cur_block = 1; cur_block < fuji_total_blocks; cur_block++) { + raw_block_offsets[cur_block] = raw_block_offsets[cur_block - 1] + block_sizes[cur_block - 1] ; + } + + xtrans_decode_loop (&common_info, fuji_total_blocks, raw_block_offsets, block_sizes); + + free (block_sizes); + free (raw_block_offsets); + free (common_info.q_table); +} + +void CLASS xtrans_decode_loop (const struct xtrans_params* common_info, int count, INT64* raw_block_offsets, unsigned *block_sizes) +{ + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int cur_block = 0; cur_block < count ; cur_block++) { + xtrans_decode_strip (common_info, cur_block, raw_block_offsets[cur_block], block_sizes[cur_block]); + } +} + + +void CLASS parse_xtrans_header() +{ + + uchar header[16]; + + ushort signature; + uchar version; + uchar h_raw_type; + uchar h_raw_bits; + ushort h_raw_height; + ushort h_raw_rounded_width; + ushort h_raw_width; + ushort h_block_size; + uchar h_blocks_in_row; + ushort h_total_lines; + + fseek (ifp, data_offset, SEEK_SET); + fread (header, 1, sizeof (header), ifp); + + signature = sgetn (2, header); + version = header[2]; + h_raw_type = header[3]; + h_raw_bits = header[4]; + h_raw_height = sgetn (2, header + 5); + h_raw_rounded_width = sgetn (2, header + 7); + h_raw_width = sgetn (2, header + 9); + h_block_size = sgetn (2, header + 11); + h_blocks_in_row = header[13]; + h_total_lines = sgetn (2, header + 14); + + + // general validation + if (signature != 0x4953 + || version != 1 + || h_raw_height > 0x3000 + || h_raw_height < 6 + || h_raw_height % 6 + || h_raw_width > 0x3000 + || h_raw_width < 0x300 + || h_raw_width % 24 + || h_raw_rounded_width > 0x3000 + || h_raw_rounded_width < h_block_size + || h_raw_rounded_width % h_block_size + || h_raw_rounded_width - h_raw_width >= h_block_size + || h_block_size != 0x300 + || h_blocks_in_row > 0x10 + || h_blocks_in_row == 0 + || h_blocks_in_row != h_raw_rounded_width / h_block_size + || h_total_lines > 0x800 + || h_total_lines == 0 + || h_total_lines != h_raw_height / 6 + || (h_raw_bits != 12 && h_raw_bits != 14) + || h_raw_type != 16) { + xtransCompressed = false; + return; + } + + // modify data + fuji_total_lines = h_total_lines; + fuji_total_blocks = h_blocks_in_row; + fuji_block_width = h_block_size; + fuji_bits = h_raw_bits; + raw_width = h_raw_width; + raw_height = h_raw_height; + data_offset += 16; + load_raw = &CLASS xtrans_compressed_load_raw; +} diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index fbe2be4c6..7bd53c444 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -85,6 +85,8 @@ BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(nullptr), fileCa BatchQueue::~BatchQueue () { + idle_register.destroy(); + MYWRITERLOCK(l, entryRW); // The listener merges parameters with old values, so delete afterwards @@ -937,7 +939,7 @@ void BatchQueue::notifyListener (bool queueEmptied) } params->queueEmptied = queueEmptied; params->queueError = false; - add_idle (bqnotifylistenerUI, params); + idle_register.add(bqnotifylistenerUI, params); } } @@ -967,6 +969,6 @@ void BatchQueue::error (Glib::ustring msg) params->queueEmptied = false; params->queueError = true; params->queueErrorMessage = msg; - add_idle (bqnotifylistenerUI, params); + idle_register.add(bqnotifylistenerUI, params); } } diff --git a/rtgui/batchqueue.h b/rtgui/batchqueue.h index f7376680b..68373838e 100644 --- a/rtgui/batchqueue.h +++ b/rtgui/batchqueue.h @@ -36,37 +36,12 @@ public: }; class FileCatalog; -class BatchQueue : public ThumbBrowserBase, + +class BatchQueue final : + public ThumbBrowserBase, public rtengine::BatchProcessingListener, public LWButtonListener { - -protected: - int getMaxThumbnailHeight() const; - void saveThumbnailHeight (int height); - int getThumbnailHeight (); - - BatchQueueEntry* processing; // holds the currently processed image - FileCatalog* fileCatalog; - int sequence; // holds the current sequence index - - Glib::ustring nameTemplate; - - MyImageMenuItem* cancel; - MyImageMenuItem* head; - MyImageMenuItem* tail; - Gtk::MenuItem* selall; - Gtk::MenuItem* open; - Glib::RefPtr pmaccelgroup; - Gtk::Menu pmenu; - - BatchQueueListener* listener; - - Glib::ustring autoCompleteFileName (const Glib::ustring& fileName, const Glib::ustring& format); - Glib::ustring getTempFilenameForParams( const Glib::ustring &filename ); - bool saveBatchQueue (); - void notifyListener (bool queueEmptied); - public: explicit BatchQueue (FileCatalog* aFileCatalog); ~BatchQueue (); @@ -106,6 +81,34 @@ public: static Glib::ustring calcAutoFileNameBase (const Glib::ustring& origFileName, int sequence = 0); static int calcMaxThumbnailHeight(); + +protected: + int getMaxThumbnailHeight() const; + void saveThumbnailHeight (int height); + int getThumbnailHeight (); + + Glib::ustring autoCompleteFileName (const Glib::ustring& fileName, const Glib::ustring& format); + Glib::ustring getTempFilenameForParams( const Glib::ustring &filename ); + bool saveBatchQueue (); + void notifyListener (bool queueEmptied); + + BatchQueueEntry* processing; // holds the currently processed image + FileCatalog* fileCatalog; + int sequence; // holds the current sequence index + + Glib::ustring nameTemplate; + + MyImageMenuItem* cancel; + MyImageMenuItem* head; + MyImageMenuItem* tail; + Gtk::MenuItem* selall; + Gtk::MenuItem* open; + Glib::RefPtr pmaccelgroup; + Gtk::Menu pmenu; + + BatchQueueListener* listener; + + IdleRegister idle_register; }; #endif diff --git a/rtgui/blackwhite.cc b/rtgui/blackwhite.cc index dab459a14..67dd9f64a 100644 --- a/rtgui/blackwhite.cc +++ b/rtgui/blackwhite.cc @@ -364,23 +364,25 @@ BlackWhite::BlackWhite (): FoldableToolPanel(this, "blackwhite", M("TP_BWMIX_LAB } BlackWhite::~BlackWhite () { + idle_register.destroy(); + delete luminanceCEG; delete beforeCurveCEG; delete afterCurveCEG; } -int BWChangedUI (void* data) -{ - (static_cast(data))->BWComputed_ (); - return 0; -} - void BlackWhite::BWChanged (double redbw, double greenbw, double bluebw) { nextredbw = redbw; nextgreenbw = greenbw; nextbluebw = bluebw; - add_idle (BWChangedUI, this); + + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->BWComputed_(); + return FALSE; + }; + + idle_register.add(func, this); } bool BlackWhite::BWComputed_ () diff --git a/rtgui/blackwhite.h b/rtgui/blackwhite.h index e38258b04..5f0ffec44 100644 --- a/rtgui/blackwhite.h +++ b/rtgui/blackwhite.h @@ -28,10 +28,64 @@ #include "mycurve.h" #include "colorprovider.h" -class BlackWhite : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoBWListener, public CurveListener, public ColorProvider +class BlackWhite final : + public ToolParamBlock, + public AdjusterListener, + public FoldableToolPanel, + public rtengine::AutoBWListener, + public CurveListener, + public ColorProvider { +public: + + BlackWhite (); + ~BlackWhite (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); + void setBatchMode (bool batchMode); + void autoOpenCurve (); + void setEditProvider (EditDataProvider *provider); + + void autoch_toggled (); + void neutral_pressed (); + + void updateRGBLabel (); + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool bwadd, bool bwgadd); + void trimValues (rtengine::procparams::ProcParams* pp); + void enabledcc_toggled (); + void enabledChanged (); + void methodChanged (); + void filterChanged (); + void settingChanged (); + virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); + void BWChanged (double redbw, double greenbw, double bluebw); + bool BWComputed_ (); + void curveChanged (CurveEditor* ce); + void curveMode1Changed (); + bool curveMode1Changed_ (); + void curveMode1Changed2 (); + bool curveMode1Changed2_ (); + void algoChanged (); + + Glib::ustring getSettingString (); + Glib::ustring getFilterString (); + Glib::ustring getalgoString (); + +private: + void showLuminance(); + void hideLuminance(); + void showFilter(); + void hideFilter(); + void showEnabledCC(); + void hideEnabledCC(); + void showMixer(int nChannels, bool RGBIsSensitive = true); + void hideMixer(); + void showGamma(); + void hideGamma(); -protected: FlatCurveEditor* luminanceCurve; Gtk::HSeparator* luminanceSep; CurveEditorGroup* luminanceCEG; @@ -85,55 +139,7 @@ protected: double nextgreenbw; double nextbluebw; - void showLuminance(); - void hideLuminance(); - void showFilter(); - void hideFilter(); - void showEnabledCC(); - void hideEnabledCC(); - void showMixer(int nChannels, bool RGBIsSensitive = true); - void hideMixer(); - void showGamma(); - void hideGamma(); - -public: - - BlackWhite (); - ~BlackWhite (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); - void setBatchMode (bool batchMode); - void autoOpenCurve (); - void setEditProvider (EditDataProvider *provider); - - void autoch_toggled (); - void neutral_pressed (); - - void updateRGBLabel (); - void adjusterChanged (Adjuster* a, double newval); - void setAdjusterBehavior (bool bwadd, bool bwgadd); - void trimValues (rtengine::procparams::ProcParams* pp); - void enabledcc_toggled (); - void enabledChanged (); - void methodChanged (); - void filterChanged (); - void settingChanged (); - virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); - void BWChanged (double redbw, double greenbw, double bluebw); - bool BWComputed_ (); - void curveChanged (CurveEditor* ce); - void curveMode1Changed (); - bool curveMode1Changed_ (); - void curveMode1Changed2 (); - bool curveMode1Changed2_ (); - void algoChanged (); - - Glib::ustring getSettingString (); - Glib::ustring getFilterString (); - Glib::ustring getalgoString (); - + IdleRegister idle_register; }; #endif diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index 7421711eb..081db2b76 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -19,6 +19,7 @@ #include "cachemanager.h" #include +#include #include #include @@ -35,8 +36,8 @@ namespace { -constexpr auto cacheDirMode = 511; -constexpr auto cacheDirs = { "profiles", "images", "aehistograms", "embprofiles", "data" }; +constexpr int cacheDirMode = 0777; +constexpr const char* cacheDirs[] = { "profiles", "images", "aehistograms", "embprofiles", "data", "mip" }; } @@ -60,7 +61,7 @@ void CacheManager::init () } if (error != 0 && options.rtSettings.verbose) { - std::cerr << "Failed to create all cache directories: " << g_strerror(errno) << std::endl; + std::cerr << "Failed to create all cache directories: " << g_strerror (errno) << std::endl; } } @@ -76,6 +77,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) // if it is open, return it const auto iterator = openEntries.find (fname); + if (iterator != openEntries.end ()) { auto cachedThumbnail = iterator->second; @@ -99,9 +101,11 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) CacheImageData imageData; const auto error = imageData.load (cacheName); + if (error == 0 && imageData.supported) { thumbnail.reset (new Thumbnail (this, fname, &imageData)); + if (!thumbnail->isSupported ()) { thumbnail.reset (); } @@ -112,6 +116,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) if (!thumbnail) { thumbnail.reset (new Thumbnail (this, fname, md5)); + if (!thumbnail->isSupported ()) { thumbnail.reset (); } @@ -123,6 +128,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) MyMutex::MyLock lock (mutex); const auto iterator = openEntries.find (fname); + if (iterator != openEntries.end ()) { auto cachedThumbnail = iterator->second; @@ -145,6 +151,7 @@ void CacheManager::deleteEntry (const Glib::ustring& fname) // check if it is opened auto iterator = openEntries.find (fname); + if (iterator == openEntries.end ()) { deleteFiles (fname, getMD5 (fname), true, true); return; @@ -190,12 +197,13 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin error |= g_rename (getCacheFileName ("data", oldfilename, ".txt", oldmd5).c_str (), getCacheFileName ("data", newfilename, ".txt", newmd5).c_str ()); if (error != 0 && options.rtSettings.verbose) { - std::cerr << "Failed to rename all files for cache entry '" << oldfilename << "': " << g_strerror(errno) << std::endl; + std::cerr << "Failed to rename all files for cache entry '" << oldfilename << "': " << g_strerror (errno) << std::endl; } // check if it is opened // if it is open, update md5 const auto iterator = openEntries.find (oldfilename); + if (iterator == openEntries.end ()) { return; } @@ -256,12 +264,13 @@ void CacheManager::deleteDir (const Glib::ustring& dirName) const Glib::Dir dir (Glib::build_filename (baseDir, dirName)); auto error = 0; + for (auto entry = dir.begin (); entry != dir.end (); ++entry) { error |= g_remove (Glib::build_filename (baseDir, dirName, *entry).c_str ()); } if (error != 0 && options.rtSettings.verbose) { - std::cerr << "Failed to delete all entries in cache directory '" << dirName << "': " << g_strerror(errno) << std::endl; + std::cerr << "Failed to delete all entries in cache directory '" << dirName << "': " << g_strerror (errno) << std::endl; } } catch (Glib::Error&) {} @@ -289,7 +298,7 @@ void CacheManager::deleteFiles (const Glib::ustring& fname, const std::string& m } if (error != 0 && options.rtSettings.verbose) { - std::cerr << "Failed to delete all files for cache entry '" << fname << "': " << g_strerror(errno) << std::endl; + std::cerr << "Failed to delete all files for cache entry '" << fname << "': " << g_strerror (errno) << std::endl; } } @@ -302,9 +311,10 @@ std::string CacheManager::getMD5 (const Glib::ustring& fname) #ifdef WIN32 - std::unique_ptr wfname (reinterpret_cast(g_utf8_to_utf16 (fname.c_str (), -1, NULL, NULL, NULL)), g_free); + std::unique_ptr wfname (reinterpret_cast (g_utf8_to_utf16 (fname.c_str (), -1, NULL, NULL, NULL)), g_free); WIN32_FILE_ATTRIBUTE_DATA fileAttr; + if (GetFileAttributesExW (wfname.get (), GetFileExInfoStandard, &fileAttr)) { // We use name, size and creation time to identify a file. const auto identifier = Glib::ustring::compose ("%1-%2-%3-%4", fileAttr.nFileSizeLow, fileAttr.ftCreationTime.dwHighDateTime, fileAttr.ftCreationTime.dwLowDateTime, fname); @@ -313,8 +323,7 @@ std::string CacheManager::getMD5 (const Glib::ustring& fname) #else - try - { + try { if (auto info = file->query_info ()) { // We only use name and size to identify a file. @@ -322,7 +331,7 @@ std::string CacheManager::getMD5 (const Glib::ustring& fname) return Glib::Checksum::compute_checksum (Glib::Checksum::CHECKSUM_MD5, identifier); } - } catch(Gio::Error&) {} + } catch (Gio::Error&) {} #endif @@ -332,9 +341,9 @@ std::string CacheManager::getMD5 (const Glib::ustring& fname) } Glib::ustring CacheManager::getCacheFileName (const Glib::ustring& subDir, - const Glib::ustring& fname, - const Glib::ustring& fext, - const Glib::ustring& md5) const + const Glib::ustring& fname, + const Glib::ustring& fext, + const Glib::ustring& md5) const { const auto dirName = Glib::build_filename (baseDir, subDir); const auto baseName = Glib::path_get_basename (fname) + "." + md5; @@ -363,8 +372,7 @@ void CacheManager::applyCacheSizeLimitation () const return; } - std::sort (files.begin (), files.end (), [] (const FNameMTime& lhs, const FNameMTime& rhs) - { + std::sort (files.begin (), files.end (), [] (const FNameMTime & lhs, const FNameMTime & rhs) { return lhs.second < rhs.second; }); diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 528047a22..a198dd1f5 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -424,6 +424,8 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel(this, "colorappearance", ColorAppearance::~ColorAppearance () { + idle_register.destroy(); + delete curveEditorG; delete curveEditorG2; delete curveEditorG3; @@ -1002,15 +1004,17 @@ void ColorAppearance::setDefaults (const ProcParams* defParams, const ParamsEdit } } -int autoCamChangedUI (void* data) -{ - (static_cast(data))->autoCamComputed_ (); - return 0; -} + void ColorAppearance::autoCamChanged (double ccam) { nextCcam = ccam; - add_idle (autoCamChangedUI, this); + + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->autoCamComputed_(); + return FALSE; + }; + + idle_register.add(func, this); } bool ColorAppearance::autoCamComputed_ () @@ -1023,15 +1027,17 @@ bool ColorAppearance::autoCamComputed_ () return false; } -int adapCamChangedUI (void* data) -{ - (static_cast(data))->adapCamComputed_ (); - return 0; -} + void ColorAppearance::adapCamChanged (double cadap) { nextCadap = cadap; - add_idle (adapCamChangedUI, this); + + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->adapCamComputed_(); + return FALSE; + }; + + idle_register.add(func, this); } bool ColorAppearance::adapCamComputed_ () diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index 1560e275e..e7b7e072d 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -28,10 +28,61 @@ #include "guiutils.h" #include "colorprovider.h" -class ColorAppearance : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoCamListener, public CurveListener, public ColorProvider +class ColorAppearance final : + public ToolParamBlock, + public AdjusterListener, + public FoldableToolPanel, + public rtengine::AutoCamListener, + public CurveListener, + public ColorProvider { +public: + ColorAppearance (); + ~ColorAppearance (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); + void setBatchMode (bool batchMode); + void adjusterChanged (Adjuster* a, double newval); + void adjusterAutoToggled (Adjuster* a, bool newval); +// void adjusterAdapToggled (Adjuster* a, bool newval); + void enabledChanged (); + void surroundChanged (); + void wbmodelChanged (); + void algoChanged (); + void surrsource_toggled (); + void gamut_toggled (); +// void badpix_toggled (); + void datacie_toggled (); + void tonecie_toggled (); +// void sharpcie_toggled (); + void autoCamChanged (double ccam); + bool autoCamComputed_ (); + void adapCamChanged (double cadap); + bool adapCamComputed_ (); + + void curveChanged (CurveEditor* ce); + void curveMode1Changed (); + bool curveMode1Changed_ (); + void curveMode2Changed (); + bool curveMode2Changed_ (); + void curveMode3Changed (); + bool curveMode3Changed_ (); + + void expandCurve (bool isExpanded); + bool isCurveExpanded (); + void autoOpenCurve (); + + void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd); + void trimValues (rtengine::procparams::ProcParams* pp); + void updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histLRETI); + virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller); + +private: + bool bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); + bool srTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); -protected: Glib::RefPtr bgTTips; Glib::RefPtr srTTips; Glib::RefPtr bgPixbuf; @@ -83,56 +134,10 @@ protected: bool lastAutoAdapscen; bool lastsurr; bool lastgamut; -// bool lastbadpix; bool lastdatacie; bool lasttonecie; -// bool lastsharpcie; - bool bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); - bool srTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); -public: - - ColorAppearance (); - ~ColorAppearance (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); - void setBatchMode (bool batchMode); - void adjusterChanged (Adjuster* a, double newval); - void adjusterAutoToggled (Adjuster* a, bool newval); -// void adjusterAdapToggled (Adjuster* a, bool newval); - void enabledChanged (); - void surroundChanged (); - void wbmodelChanged (); - void algoChanged (); - void surrsource_toggled (); - void gamut_toggled (); -// void badpix_toggled (); - void datacie_toggled (); - void tonecie_toggled (); -// void sharpcie_toggled (); - void autoCamChanged (double ccam); - bool autoCamComputed_ (); - void adapCamChanged (double cadap); - bool adapCamComputed_ (); - - void curveChanged (CurveEditor* ce); - void curveMode1Changed (); - bool curveMode1Changed_ (); - void curveMode2Changed (); - bool curveMode2Changed_ (); - void curveMode3Changed (); - bool curveMode3Changed_ (); - - void expandCurve (bool isExpanded); - bool isCurveExpanded (); - void autoOpenCurve (); - - void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd); - void trimValues (rtengine::procparams::ProcParams* pp); - void updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histLRETI); - virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller); + IdleRegister idle_register; }; #endif diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index ceec0092f..d471ef787 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -324,6 +324,8 @@ ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLOR ColorToning::~ColorToning() { + idle_register.destroy(); + delete colorCurveEditorG; delete opacityCurveEditorG; delete clCurveEditorG; @@ -650,19 +652,18 @@ void ColorToning::adjusterChanged (ThresholdAdjuster* a, double newBottom, doubl Glib::ustring::compose(Glib::ustring(M("TP_COLORTONING_HUE") + ": %1" + "\n" + M("TP_COLORTONING_STRENGTH") + ": %2"), int(newTop), int(newBottom))); } -int CTChanged_UI (void* data) -{ - (static_cast(data))->CTComp_ (); - return 0; -} - - void ColorToning::autoColorTonChanged(int bwct, int satthres, int satprot) { nextbw = bwct; nextsatth = satthres; nextsatpr = satprot; - add_idle (CTChanged_UI, this); + + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->CTComp_(); + return FALSE; + }; + + idle_register.add(func, this); } bool ColorToning::CTComp_ () diff --git a/rtgui/colortoning.h b/rtgui/colortoning.h index e34447301..7f1290bf6 100644 --- a/rtgui/colortoning.h +++ b/rtgui/colortoning.h @@ -13,12 +13,43 @@ #include "thresholdadjuster.h" #include "colorprovider.h" -class ColorToning : public ToolParamBlock, public FoldableToolPanel, public rtengine::AutoColorTonListener, public CurveListener, public ColorProvider, - public ThresholdAdjusterListener, public AdjusterListener +class ColorToning final : + public ToolParamBlock, + public FoldableToolPanel, + public rtengine::AutoColorTonListener, + public CurveListener, + public ColorProvider, + public ThresholdAdjusterListener, + public AdjusterListener { +public: + ColorToning (); + ~ColorToning(); + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); + void trimValues (rtengine::procparams::ProcParams* pp); + void adjusterChanged (Adjuster* a, double newval); + void adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop); + void setAdjusterBehavior (bool splitAdd, bool satThresholdAdd, bool satOpacityAdd, bool strprotectAdd, bool balanceAdd); + void neutral_pressed (); + //void neutralCurves_pressed (); + void autoColorTonChanged (int bwct, int satthres, int satprot); + bool CTComp_ (); -protected: - //Gtk::HSeparator* splitSep; + void enabledChanged (); + void curveChanged (CurveEditor* ce); + void autosatChanged (); + void autoOpenCurve (); + void methodChanged (); + void twocolorChanged (bool changedbymethod); + void twoColorChangedByGui (); + void lumamodeChanged (); + + void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); + +private: Gtk::HSeparator* satLimiterSep; Gtk::HSeparator* colorSep; CurveEditorGroup* colorCurveEditorG; @@ -57,7 +88,6 @@ protected: Gtk::Image* irg; Gtk::Button* neutral; - //Gtk::Button* neutralCurves; Gtk::HBox* neutrHBox; Gtk::HBox* chromaHbox; Gtk::Label* chroLabel; @@ -75,32 +105,7 @@ protected: bool lastLumamode; sigc::connection lumamodeConn; -public: - ColorToning (); - ~ColorToning(); - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); - void trimValues (rtengine::procparams::ProcParams* pp); - void adjusterChanged (Adjuster* a, double newval); - void adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop); - void setAdjusterBehavior (bool splitAdd, bool satThresholdAdd, bool satOpacityAdd, bool strprotectAdd, bool balanceAdd); - void neutral_pressed (); - //void neutralCurves_pressed (); - void autoColorTonChanged (int bwct, int satthres, int satprot); - bool CTComp_ (); - - void enabledChanged (); - void curveChanged (CurveEditor* ce); - void autosatChanged (); - void autoOpenCurve (); - void methodChanged (); - void twocolorChanged (bool changedbymethod); - void twoColorChangedByGui (); - void lumamodeChanged (); - - void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); + IdleRegister idle_register; }; #endif diff --git a/rtgui/crop.cc b/rtgui/crop.cc index a69c71ed8..83efb6a37 100644 --- a/rtgui/crop.cc +++ b/rtgui/crop.cc @@ -25,6 +25,9 @@ using namespace rtengine::procparams; extern Options options; +namespace +{ + class RefreshSpinHelper { @@ -35,6 +38,22 @@ public: : crop(_crop), notify(_notify) {} }; +int refreshSpinsUI (void* data) +{ + RefreshSpinHelper* rsh = static_cast(data); + rsh->crop->refreshSpins (rsh->notify); + delete rsh; + return 0; +} + +int notifyListenerUI (void* data) +{ + static_cast(data)->notifyListener(); + return 0; +} + +} + Crop::Crop (): FoldableToolPanel(this, "crop", M("TP_CROP_LABEL"), false, true) { @@ -252,6 +271,11 @@ Crop::Crop (): FoldableToolPanel(this, "crop", M("TP_CROP_LABEL"), false, true) show_all (); } +Crop::~Crop() +{ + idle_register.destroy(); +} + void Crop::writeOptions () { @@ -508,32 +532,18 @@ void Crop::enabledChanged () } } -int notifyListenerUI (void* data) -{ - (static_cast(data))->notifyListener (); - return 0; -} - -int refreshSpinsUI (void* data) -{ - RefreshSpinHelper* rsh = static_cast(data); - rsh->crop->refreshSpins (rsh->notify); - delete rsh; - return 0; -} - void Crop::hFlipCrop () { nx = maxw - nx - nw; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::vFlipCrop () { ny = maxh - ny - nh; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::rotateCrop (int deg, bool hflip, bool vflip) @@ -573,7 +583,7 @@ void Crop::rotateCrop (int deg, bool hflip, bool vflip) } lastRotationDeg = deg; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::positionChanged () @@ -587,7 +597,7 @@ void Crop::positionChanged () int W = nw; int H = nh; cropMoved (X, Y, W, H); - add_idle (notifyListenerUI, this); + idle_register.add(notifyListenerUI, this); } void Crop::widthChanged () @@ -600,7 +610,7 @@ void Crop::widthChanged () int W = (int)w->get_value (); int H = nh; cropWidth2Resized (X, Y, W, H); - add_idle (notifyListenerUI, this); + idle_register.add(notifyListenerUI, this); } void Crop::heightChanged () @@ -613,7 +623,7 @@ void Crop::heightChanged () int W = nw; int H = (int)h->get_value (); cropHeight2Resized (X, Y, W, H); - add_idle (notifyListenerUI, this); + idle_register.add(notifyListenerUI, this); } // Fixed ratio toggle button @@ -665,7 +675,7 @@ void Crop::adjustCropToRatio() } // This will save the options - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, true)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, true)); } void Crop::refreshSize () @@ -737,28 +747,28 @@ void Crop::setDimensions (int mw, int mh) refreshSize (); } -struct setdimparams { - Crop* crop; - int x; - int y; -}; - -int sizeChangedUI (void* data) -{ - setdimparams* params = static_cast(data); - params->crop->setDimensions (params->x, params->y); - delete params; - return 0; -} - void Crop::sizeChanged (int x, int y, int ow, int oh) { + struct Params { + Crop* crop; + int x; + int y; + }; - setdimparams* params = new setdimparams; - params->x = x; - params->y = y; - params->crop = this; - add_idle (sizeChangedUI, params); + Params* const params = new Params{ + this, + x, + y + }; + + const auto func = [](gpointer data) -> gboolean { + Params* const params = static_cast(data); + params->crop->setDimensions(params->x, params->y); + delete params; + return FALSE; + }; + + idle_register.add(func, params); } bool Crop::refreshSpins (bool notify) @@ -822,7 +832,7 @@ void Crop::cropMoved (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); // Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins)); } @@ -866,7 +876,7 @@ void Crop::cropWidth1Resized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropWidth2Resized (int &X, int &Y, int &W, int &H) @@ -906,7 +916,7 @@ void Crop::cropWidth2Resized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropHeight1Resized (int &X, int &Y, int &W, int &H) @@ -949,7 +959,7 @@ void Crop::cropHeight1Resized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropHeight2Resized (int &X, int &Y, int &W, int &H) @@ -989,7 +999,7 @@ void Crop::cropHeight2Resized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropTopLeftResized (int &X, int &Y, int &W, int &H) @@ -1031,7 +1041,7 @@ void Crop::cropTopLeftResized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropTopRightResized (int &X, int &Y, int &W, int &H) @@ -1071,7 +1081,7 @@ void Crop::cropTopRightResized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropBottomLeftResized (int &X, int &Y, int &W, int &H) @@ -1111,7 +1121,7 @@ void Crop::cropBottomLeftResized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropBottomRightResized (int &X, int &Y, int &W, int &H) @@ -1148,7 +1158,7 @@ void Crop::cropBottomRightResized (int &X, int &Y, int &W, int &H) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropInit (int &x, int &y, int &w, int &h) @@ -1266,13 +1276,12 @@ void Crop::cropResized (int &x, int &y, int& x2, int& y2) nw = W; nh = H; - add_idle (refreshSpinsUI, new RefreshSpinHelper (this, false)); + idle_register.add(refreshSpinsUI, new RefreshSpinHelper(this, false)); } void Crop::cropManipReady () { - - add_idle (notifyListenerUI, this); + idle_register.add(notifyListenerUI, this); } double Crop::getRatio () diff --git a/rtgui/crop.h b/rtgui/crop.h index 077903836..e0bad8b36 100644 --- a/rtgui/crop.h +++ b/rtgui/crop.h @@ -33,44 +33,20 @@ public: virtual void cropSelectRequested() = 0; }; -class CropRatio -{ - -public: +struct CropRatio { Glib::ustring label; double value; }; -class Crop : public ToolParamBlock, public CropGUIListener, public FoldableToolPanel, public rtengine::SizeListener +class Crop final : + public ToolParamBlock, + public CropGUIListener, + public FoldableToolPanel, + public rtengine::SizeListener { -protected: - Gtk::CheckButton* fixr; - MyComboBoxText* ratio; - MyComboBoxText* orientation; - MyComboBoxText* guide; - Gtk::Button* selectCrop; - CropPanelListener* clistener; - int opt; - MySpinButton* x; - MySpinButton* y; - MySpinButton* w; - MySpinButton* h; - MySpinButton* ppi; - Gtk::Label* sizecm; - Gtk::Label* sizein; - Gtk::VBox* ppibox; - Gtk::VBox* sizebox; - int maxw, maxh; - double nx, ny; - int nw, nh; - int lastRotationDeg; - sigc::connection xconn, yconn, wconn, hconn, fconn, rconn, oconn, gconn; - bool wDirty, hDirty, xDirty, yDirty, lastFixRatio; - void adjustCropToRatio(); - std::vector cropratio; - public: - Crop (); + Crop(); + ~Crop(); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); @@ -116,6 +92,34 @@ public: void hFlipCrop (); void vFlipCrop (); void rotateCrop (int deg, bool hflip, bool vflip); + +private: + Gtk::CheckButton* fixr; + MyComboBoxText* ratio; + MyComboBoxText* orientation; + MyComboBoxText* guide; + Gtk::Button* selectCrop; + CropPanelListener* clistener; + int opt; + MySpinButton* x; + MySpinButton* y; + MySpinButton* w; + MySpinButton* h; + MySpinButton* ppi; + Gtk::Label* sizecm; + Gtk::Label* sizein; + Gtk::VBox* ppibox; + Gtk::VBox* sizebox; + int maxw, maxh; + double nx, ny; + int nw, nh; + int lastRotationDeg; + sigc::connection xconn, yconn, wconn, hconn, fconn, rconn, oconn, gconn; + bool wDirty, hDirty, xDirty, yDirty, lastFixRatio; + void adjustCropToRatio(); + std::vector cropratio; + + IdleRegister idle_register; }; #endif diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index bb59efe13..42c6eb756 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -38,14 +38,15 @@ CropHandler::CropHandler () displayHandler(nullptr) { - chi = new CropHandlerIdleHelper; - chi->destroyed = false; - chi->pending = 0; - chi->cropHandler = this; + idle_helper = new IdleHelper; + idle_helper->destroyed = false; + idle_helper->pending = 0; + idle_helper->cropHandler = this; } CropHandler::~CropHandler () { + idle_register.destroy(); if (ipc) { ipc->delSizeListener (this); @@ -61,10 +62,10 @@ CropHandler::~CropHandler () cimg.lock (); - if (chi->pending) { - chi->destroyed = true; + if (idle_helper->pending) { + idle_helper->destroyed = true; } else { - delete chi; + delete idle_helper; } cimg.unlock (); @@ -292,83 +293,6 @@ void CropHandler::getPosition (int& x, int& y) } -int createpixbufs (void* data) -{ - - CropHandlerIdleHelper* chi = static_cast(data); - - if (chi->destroyed) { - if (chi->pending == 1) { - delete chi; - } else { - chi->pending--; - } - - return 0; - } - - CropHandler* ch = chi->cropHandler; - - ch->cimg.lock (); - ch->cropPixbuf.clear (); - - if (!ch->enabled) { - delete [] ch->cropimg; - ch->cropimg = nullptr; - delete [] ch->cropimgtrue; - ch->cropimgtrue = nullptr; - ch->cimg.unlock (); - return 0; - } - - if (ch->cropimg) { - if (ch->cix == ch->cropX && ch->ciy == ch->cropY && ch->ciw == ch->cropW && ch->cih == ch->cropH && ch->cis == (ch->zoom >= 1000 ? 1 : ch->zoom)) { - // calculate final image size - int czoom = ch->zoom < 1000 ? 1000 : ch->zoom; - int imw = ch->cropimg_width * czoom / 1000; - int imh = ch->cropimg_height * czoom / 1000; - - if (imw > ch->ww) { - imw = ch->ww; - } - - if (imh > ch->wh) { - imh = ch->wh; - } - - Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2 * ch->cropimg_height, 3 * ch->cropimg_width); - ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); - tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom / 1000.0, czoom / 1000.0, Gdk::INTERP_NEAREST); - tmpPixbuf.clear (); - - Glib::RefPtr tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2 * ch->cropimg_height, 3 * ch->cropimg_width); - ch->cropPixbuftrue = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); - tmpPixbuftrue->scale (ch->cropPixbuftrue, 0, 0, imw, imh, 0, 0, czoom / 1000.0, czoom / 1000.0, Gdk::INTERP_NEAREST); - tmpPixbuftrue.clear (); - } - - delete [] ch->cropimg; - ch->cropimg = nullptr; - delete [] ch->cropimgtrue; - ch->cropimgtrue = nullptr; - } - - ch->cimg.unlock (); - - if (ch->displayHandler) { - ch->displayHandler->cropImageUpdated (); - - if (ch->initial) { - ch->displayHandler->initialImageArrived (); - ch->initial = false; - } - } - - chi->pending--; - - return 0; -} - void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procparams::ColorManagementParams cmp, rtengine::procparams::CropParams cp, int ax, int ay, int aw, int ah, int askip) { @@ -408,8 +332,84 @@ void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procp ciw = aw; cih = ah; cis = askip; - chi->pending++; - add_idle (createpixbufs, chi); + idle_helper->pending++; + + const auto func = [](gpointer data) -> gboolean { + IdleHelper* const idle_helper = static_cast(data); + + if (idle_helper->destroyed) { + if (idle_helper->pending == 1) { + delete idle_helper; + } else { + idle_helper->pending--; + } + + return FALSE; + } + + CropHandler* ch = idle_helper->cropHandler; + + ch->cimg.lock (); + ch->cropPixbuf.clear (); + + if (!ch->enabled) { + delete [] ch->cropimg; + ch->cropimg = nullptr; + delete [] ch->cropimgtrue; + ch->cropimgtrue = nullptr; + ch->cimg.unlock (); + return FALSE; + } + + if (ch->cropimg) { + if (ch->cix == ch->cropX && ch->ciy == ch->cropY && ch->ciw == ch->cropW && ch->cih == ch->cropH && ch->cis == (ch->zoom >= 1000 ? 1 : ch->zoom)) { + // calculate final image size + int czoom = ch->zoom < 1000 ? 1000 : ch->zoom; + int imw = ch->cropimg_width * czoom / 1000; + int imh = ch->cropimg_height * czoom / 1000; + + if (imw > ch->ww) { + imw = ch->ww; + } + + if (imh > ch->wh) { + imh = ch->wh; + } + + Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2 * ch->cropimg_height, 3 * ch->cropimg_width); + ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); + tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom / 1000.0, czoom / 1000.0, Gdk::INTERP_NEAREST); + tmpPixbuf.clear (); + + Glib::RefPtr tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2 * ch->cropimg_height, 3 * ch->cropimg_width); + ch->cropPixbuftrue = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); + tmpPixbuftrue->scale (ch->cropPixbuftrue, 0, 0, imw, imh, 0, 0, czoom / 1000.0, czoom / 1000.0, Gdk::INTERP_NEAREST); + tmpPixbuftrue.clear (); + } + + delete [] ch->cropimg; + ch->cropimg = nullptr; + delete [] ch->cropimgtrue; + ch->cropimgtrue = nullptr; + } + + ch->cimg.unlock (); + + if (ch->displayHandler) { + ch->displayHandler->cropImageUpdated (); + + if (ch->initial) { + ch->displayHandler->initialImageArrived (); + ch->initial = false; + } + } + + idle_helper->pending--; + + return FALSE; + }; + + idle_register.add(func, idle_helper); } cimg.unlock (); diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index 3bf7e58da..0492aea2a 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -36,56 +36,15 @@ public: virtual void setDisplayPosition (int x, int y) {} }; -class CropHandler; -struct CropHandlerIdleHelper { - CropHandler* cropHandler; - bool destroyed; - int pending; -}; - /** * This class handle the displayed part of the image, ask for the initial data and process it so it can display it. * Its position on the preview is handled not set by this class but by the CropHandlerListener (i.e. CropWindow) with which it works closely. */ -class CropHandler : public rtengine::DetailedCropListener, public rtengine::SizeListener +class CropHandler final : + public rtengine::DetailedCropListener, + public rtengine::SizeListener { - - friend int createpixbufs (void* data); - -protected: - int zoom; // scale factor (e.g. 5 if 1:5 scale) ; if 1:1 scale and bigger, factor is multiplied by 1000 (i.e. 1000 for 1:1 scale, 2000 for 2:1, etc...) - int ww, wh; // size of the crop's canvas on the screen ; might be bigger than the displayed image, but not smaller - int imx, imy, imw, imh; // this is a copy of the cropwindow's parameters - int cax, cay; // clamped crop anchor's coordinate, i.e. point of the image that coincide to the center of the display area, expressed in image coordinates; cannot be outside the image's bounds; but if cax==cay==-1, designate the center of the image - int cx, cy, cw, ch; // position and size of the requested crop ; position expressed in image coordinates, so cx and cy might be negative and cw and ch higher than the image's 1:1 size - int cropX, cropY, cropW, cropH; // cropPixbuf's displayed area (position and size), i.e. coordinates in 1:1 scale, i.e. cx, cy, cw & ch trimmed to the image's bounds - bool enabled; - unsigned char* cropimg; - unsigned char* cropimgtrue; - int cropimg_width, cropimg_height, cix, ciy, ciw, cih, cis; - bool initial; - bool isLowUpdatePriority; - - rtengine::StagedImageProcessor* ipc; - rtengine::DetailedCrop* crop; - - CropDisplayHandler* displayHandler; - CropHandlerIdleHelper* chi; - - void compDim (); - public: - - void update (); - - - rtengine::procparams::CropParams cropParams; - rtengine::procparams::ColorManagementParams colorParams; - Glib::RefPtr cropPixbuf; - Glib::RefPtr cropPixbuftrue; - - MyMutex cimg; - CropHandler (); ~CropHandler (); @@ -127,6 +86,46 @@ public: bool getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip); // SizeListener interface void sizeChanged (int w, int h, int ow, int oh); + + void update (); + + + rtengine::procparams::CropParams cropParams; + rtengine::procparams::ColorManagementParams colorParams; + Glib::RefPtr cropPixbuf; + Glib::RefPtr cropPixbuftrue; + + MyMutex cimg; + +private: + struct IdleHelper { + CropHandler* cropHandler; + bool destroyed; + int pending; + }; + + void compDim (); + + int zoom; // scale factor (e.g. 5 if 1:5 scale) ; if 1:1 scale and bigger, factor is multiplied by 1000 (i.e. 1000 for 1:1 scale, 2000 for 2:1, etc...) + int ww, wh; // size of the crop's canvas on the screen ; might be bigger than the displayed image, but not smaller + int imx, imy, imw, imh; // this is a copy of the cropwindow's parameters + int cax, cay; // clamped crop anchor's coordinate, i.e. point of the image that coincide to the center of the display area, expressed in image coordinates; cannot be outside the image's bounds; but if cax==cay==-1, designate the center of the image + int cx, cy, cw, ch; // position and size of the requested crop ; position expressed in image coordinates, so cx and cy might be negative and cw and ch higher than the image's 1:1 size + int cropX, cropY, cropW, cropH; // cropPixbuf's displayed area (position and size), i.e. coordinates in 1:1 scale, i.e. cx, cy, cw & ch trimmed to the image's bounds + bool enabled; + unsigned char* cropimg; + unsigned char* cropimgtrue; + int cropimg_width, cropimg_height, cix, ciy, ciw, cih, cis; + bool initial; + bool isLowUpdatePriority; + + rtengine::StagedImageProcessor* ipc; + rtengine::DetailedCrop* crop; + + CropDisplayHandler* displayHandler; + IdleHelper* idle_helper; + + IdleRegister idle_register; }; #endif diff --git a/rtgui/dirbrowser.cc b/rtgui/dirbrowser.cc index eafaa477a..7b5adade2 100644 --- a/rtgui/dirbrowser.cc +++ b/rtgui/dirbrowser.cc @@ -18,6 +18,7 @@ */ #include "dirbrowser.h" +#include #include #ifdef WIN32 diff --git a/rtgui/dirpyrdenoise.cc b/rtgui/dirpyrdenoise.cc index a5611cc45..bd673e5c3 100644 --- a/rtgui/dirpyrdenoise.cc +++ b/rtgui/dirpyrdenoise.cc @@ -327,22 +327,24 @@ DirPyrDenoise::DirPyrDenoise () : FoldableToolPanel(this, "dirpyrdenoise", M("TP DirPyrDenoise::~DirPyrDenoise () { + idle_register.destroy(); + delete NoiscurveEditorG; delete CCcurveEditorG; +} -} -int chromaChangedUI (void* data) -{ - (static_cast(data))->chromaComputed_ (); - return 0; -} void DirPyrDenoise::chromaChanged (double autchroma, double autred, double autblue) { nextchroma = autchroma; -// printf("CHROM=%f\n",nextchroma); nextred = autred; nextblue = autblue; - add_idle(chromaChangedUI, this); + + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->chromaComputed_(); + return false; + }; + + idle_register.add(func, this); } bool DirPyrDenoise::chromaComputed_ () @@ -356,12 +358,6 @@ bool DirPyrDenoise::chromaComputed_ () updateNoiseLabel (); return false; } -int TilePrevChangedUI (void* data) -{ - (static_cast(data))->TilePrevComputed_ (); - return 0; -} - void DirPyrDenoise::noiseTilePrev (int tileX, int tileY, int prevX, int prevY, int sizeT, int sizeP) { @@ -372,10 +368,14 @@ void DirPyrDenoise::noiseTilePrev (int tileX, int tileY, int prevX, int prevY, i nextsizeT = sizeT; nextsizeP = sizeP; - add_idle(TilePrevChangedUI, this); - + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->TilePrevComputed_(); + return false; + }; + idle_register.add(func, this); } + bool DirPyrDenoise::TilePrevComputed_ () { @@ -385,6 +385,7 @@ bool DirPyrDenoise::TilePrevComputed_ () updatePrevLabel (); return false; } + void DirPyrDenoise::updateTileLabel () { if (!batchMode) { @@ -422,19 +423,17 @@ void DirPyrDenoise::updatePrevLabel () } } - -int noiseChangedUI (void* data) -{ - (static_cast(data))->noiseComputed_ (); - return 0; -} - - void DirPyrDenoise::noiseChanged (double nresid, double highresid) { nextnresid = nresid; nexthighresid = highresid; - add_idle(noiseChangedUI, this); + + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->noiseComputed_(); + return false; + }; + + idle_register.add(func, this); } bool DirPyrDenoise::noiseComputed_ () diff --git a/rtgui/dirpyrdenoise.h b/rtgui/dirpyrdenoise.h index e81bf263e..9745b374b 100644 --- a/rtgui/dirpyrdenoise.h +++ b/rtgui/dirpyrdenoise.h @@ -28,10 +28,58 @@ #include "guiutils.h" #include "options.h" -class DirPyrDenoise : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoChromaListener, public CurveListener, public ColorProvider +class DirPyrDenoise final : + public ToolParamBlock, + public AdjusterListener, + public FoldableToolPanel, + public rtengine::AutoChromaListener, + public CurveListener, + public ColorProvider { +public: + DirPyrDenoise (); + ~DirPyrDenoise (); -protected: + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); + void setBatchMode (bool batchMode); + void curveChanged (CurveEditor* ce); + void setEditProvider (EditDataProvider *provider); + void autoOpenCurve (); + + void adjusterChanged (Adjuster* a, double newval); + void enabledChanged (); + void enhanceChanged (); + void medianChanged (); + void autochromaChanged (); + void chromaChanged (double autchroma, double autred, double autblue); + bool chromaComputed_ (); + void noiseChanged (double nresid, double highresid); + bool noiseComputed_ (); + void noiseTilePrev (int tileX, int tileY, int prevX, int prevY, int sizeT, int sizeP); + bool TilePrevComputed_ (); + +// void perform_toggled (); + void updateNoiseLabel (); + void LmethodChanged (); + void CmethodChanged (); + void C2methodChanged (); + void updateTileLabel (); + void updatePrevLabel (); + + void dmethodChanged (); + void medmethodChanged (); + void methodmedChanged (); + void rgbmethodChanged (); + void smethodChanged (); + virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); + + void setAdjusterBehavior (bool lumaadd, bool lumdetadd, bool chromaadd, bool chromaredadd, bool chromablueadd, bool gammaadd, bool passesadd); + void trimValues (rtengine::procparams::ProcParams* pp); + Glib::ustring getSettingString (); + +private: CurveEditorGroup* NoiscurveEditorG; CurveEditorGroup* CCcurveEditorG; Adjuster* luma; @@ -92,50 +140,7 @@ protected: int nextsizeT; int nextsizeP; -public: - - DirPyrDenoise (); - ~DirPyrDenoise (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); - void setBatchMode (bool batchMode); - void curveChanged (CurveEditor* ce); - void setEditProvider (EditDataProvider *provider); - void autoOpenCurve (); - - void adjusterChanged (Adjuster* a, double newval); - void enabledChanged (); - void enhanceChanged (); - void medianChanged (); - void autochromaChanged (); - void chromaChanged (double autchroma, double autred, double autblue); - bool chromaComputed_ (); - void noiseChanged (double nresid, double highresid); - bool noiseComputed_ (); - void noiseTilePrev (int tileX, int tileY, int prevX, int prevY, int sizeT, int sizeP); - bool TilePrevComputed_ (); - -// void perform_toggled (); - void updateNoiseLabel (); - void LmethodChanged (); - void CmethodChanged (); - void C2methodChanged (); - void updateTileLabel (); - void updatePrevLabel (); - - void dmethodChanged (); - void medmethodChanged (); - void methodmedChanged (); - void rgbmethodChanged (); - void smethodChanged (); - virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); - - void setAdjusterBehavior (bool lumaadd, bool lumdetadd, bool chromaadd, bool chromaredadd, bool chromablueadd, bool gammaadd, bool passesadd); - void trimValues (rtengine::procparams::ProcParams* pp); - Glib::ustring getSettingString (); - + IdleRegister idle_register; }; #endif diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 0783efe14..8da176fc3 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -35,6 +35,44 @@ using namespace rtengine::procparams; +namespace +{ + +struct spparams { + double val; + Glib::ustring str; + MyProgressBar *pProgress; + Glib::RefPtr cssProvider; +}; + +int setprogressStrUI ( void *p ) +{ + spparams *s = static_cast (p); + + if ( ! s->str.empty() ) { + s->pProgress->set_text ( M (s->str) ); + } + + if ( s->val >= 0 ) { + s->pProgress->set_fraction ( s->val ); + + if (s->cssProvider) { + if ( s->val < 1.0 ) { + s->cssProvider->load_from_data ("ProgressBar { background-color: red }"); + } else { + s->cssProvider->load_from_data ("ProgressBar { background-color: grey }"); + } + + s->pProgress->get_style_context()->set_background (s->pProgress->get_window()); + } + } + + delete s; + return FALSE; +} + +} + class EditorPanel::ColorManagementToolbar { private: @@ -683,6 +721,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) EditorPanel::~EditorPanel () { + idle_register.destroy(); history->setHistoryBeforeLineListener (nullptr); // the order is important! @@ -1017,46 +1056,12 @@ void EditorPanel::setProgressState (bool inProcessing) g_idle_add (setProgressStateUIThread, p); } -struct spparams { - double val; - Glib::ustring str; - MyProgressBar *pProgress; - Glib::RefPtr cssProvider; - -}; - -int setprogressStrUI ( void *p ) -{ - spparams *s = static_cast (p); - - if ( ! s->str.empty() ) { - s->pProgress->set_text ( M (s->str) ); - } - - if ( s->val >= 0 ) { - s->pProgress->set_fraction ( s->val ); - - if (s->cssProvider) { - if ( s->val < 1.0 ) { - s->cssProvider->load_from_data ("ProgressBar { background-color: red }"); - } else { - s->cssProvider->load_from_data ("ProgressBar { background-color: grey }"); - } - - s->pProgress->get_style_context()->set_background (s->pProgress->get_window()); - } - } - - delete s; - return 0; -} - void EditorPanel::setProgress (double p) { spparams *s = new spparams; s->val = p; s->pProgress = progressLabel; - add_idle (setprogressStrUI, s); + idle_register.add(setprogressStrUI, s); } void EditorPanel::setProgressStr (Glib::ustring str) @@ -1065,7 +1070,7 @@ void EditorPanel::setProgressStr (Glib::ustring str) s->str = str; s->val = -1; s->pProgress = progressLabel; - add_idle (setprogressStrUI, s); + idle_register.add(setprogressStrUI, s); } // This is only called from the ThreadUI, so within the gtk thread diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index d87f12c23..609df5236 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -45,102 +45,17 @@ struct EditorPanelIdleHelper { }; class RTWindow; -class EditorPanel : public Gtk::VBox, +class EditorPanel final : + public Gtk::VBox, public PParamsChangeListener, public rtengine::ProgressListener, public ThumbnailListener, public HistoryBeforeLineListener, public rtengine::HistogramListener { -private: - - Glib::ustring lastSaveAsFileName; - bool realized; - -protected: - MyProgressBar *progressLabel; - Gtk::ToggleButton* info; - Gtk::ToggleButton* hidehp; - Gtk::ToggleButton* tbShowHideSidePanels; - Gtk::ToggleButton* tbTopPanel_1; - Gtk::ToggleButton* tbRightPanel_1; - Gtk::ToggleButton* tbBeforeLock; - //bool bAllSidePanelsVisible; - Gtk::ToggleButton* beforeAfter; - Gtk::Paned* hpanedl; - Gtk::Paned* hpanedr; - Gtk::Image *iHistoryShow, *iHistoryHide; - Gtk::Image *iTopPanel_1_Show, *iTopPanel_1_Hide; - Gtk::Image *iRightPanel_1_Show, *iRightPanel_1_Hide; - Gtk::Image *iShowHideSidePanels; - Gtk::Image *iShowHideSidePanels_exit; - Gtk::Image *iBeforeLockON, *iBeforeLockOFF; - Gtk::VBox *leftbox; - Gtk::VBox *vboxright; - - Gtk::Button* queueimg; - Gtk::Button* saveimgas; - Gtk::Button* sendtogimp; - Gtk::Button* navSync; - Gtk::Button* navNext; - Gtk::Button* navPrev; - - class ColorManagementToolbar; - std::unique_ptr colorMgmtToolBar; - - ImageAreaPanel* iareapanel; - PreviewHandler* previewHandler; - PreviewHandler* beforePreviewHandler; // for the before-after view - Navigator* navigator; - ImageAreaPanel* beforeIarea; // for the before-after view - Gtk::VBox* beforeBox; - Gtk::VBox* afterBox; - Gtk::Label* beforeLabel; - Gtk::Label* afterLabel; - Gtk::HBox* beforeAfterBox; - Gtk::HBox* beforeHeaderBox; - Gtk::HBox* afterHeaderBox; - - Gtk::Frame* ppframe; - ProfilePanel* profilep; - History* history; - HistogramPanel* histogramPanel; - ToolPanelCoordinator* tpc; - RTWindow* parent; - //SaveAsDialog* saveAsDialog; - BatchToolPanelCoordinator* btpCoordinator; - FilePanel* fPanel; - - bool firstProcessingDone; - - Thumbnail* openThm; // may get invalid on external delete event - Glib::ustring fname; // must be saved separately - - rtengine::InitialImage* isrc; - rtengine::StagedImageProcessor* ipc; - rtengine::StagedImageProcessor* beforeIpc; // for the before-after view - - EditorPanelIdleHelper* epih; - - void close (); - - BatchQueueEntry* createBatchQueueEntry (); - bool idle_imageSaved (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring fname, SaveFormat sf); - bool idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf); - bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname); - bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring filename); - int err; - - time_t processingStartedTime; - - sigc::connection ShowHideSidePanelsconn; - - bool isProcessing; - - public: explicit EditorPanel (FilePanel* filePanel = nullptr); - virtual ~EditorPanel (); + ~EditorPanel (); void open (Thumbnail* tmb, rtengine::InitialImage* isrc); void setAspect (); @@ -214,7 +129,93 @@ public: void updateTabsUsesIcons (bool useIcons); void updateHistogramPosition (int oldPosition, int newPosition); - Gtk::Paned *catalogPane; + Gtk::Paned* catalogPane; + +private: + void close (); + + BatchQueueEntry* createBatchQueueEntry (); + bool idle_imageSaved (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring fname, SaveFormat sf); + bool idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf); + bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname); + bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring filename); + + Glib::ustring lastSaveAsFileName; + bool realized; + + MyProgressBar *progressLabel; + Gtk::ToggleButton* info; + Gtk::ToggleButton* hidehp; + Gtk::ToggleButton* tbShowHideSidePanels; + Gtk::ToggleButton* tbTopPanel_1; + Gtk::ToggleButton* tbRightPanel_1; + Gtk::ToggleButton* tbBeforeLock; + //bool bAllSidePanelsVisible; + Gtk::ToggleButton* beforeAfter; + Gtk::Paned* hpanedl; + Gtk::Paned* hpanedr; + Gtk::Image *iHistoryShow, *iHistoryHide; + Gtk::Image *iTopPanel_1_Show, *iTopPanel_1_Hide; + Gtk::Image *iRightPanel_1_Show, *iRightPanel_1_Hide; + Gtk::Image *iShowHideSidePanels; + Gtk::Image *iShowHideSidePanels_exit; + Gtk::Image *iBeforeLockON, *iBeforeLockOFF; + Gtk::VBox *leftbox; + Gtk::VBox *vboxright; + + Gtk::Button* queueimg; + Gtk::Button* saveimgas; + Gtk::Button* sendtogimp; + Gtk::Button* navSync; + Gtk::Button* navNext; + Gtk::Button* navPrev; + + class ColorManagementToolbar; + std::unique_ptr colorMgmtToolBar; + + ImageAreaPanel* iareapanel; + PreviewHandler* previewHandler; + PreviewHandler* beforePreviewHandler; // for the before-after view + Navigator* navigator; + ImageAreaPanel* beforeIarea; // for the before-after view + Gtk::VBox* beforeBox; + Gtk::VBox* afterBox; + Gtk::Label* beforeLabel; + Gtk::Label* afterLabel; + Gtk::HBox* beforeAfterBox; + Gtk::HBox* beforeHeaderBox; + Gtk::HBox* afterHeaderBox; + + Gtk::Frame* ppframe; + ProfilePanel* profilep; + History* history; + HistogramPanel* histogramPanel; + ToolPanelCoordinator* tpc; + RTWindow* parent; + //SaveAsDialog* saveAsDialog; + BatchToolPanelCoordinator* btpCoordinator; + FilePanel* fPanel; + + bool firstProcessingDone; + + Thumbnail* openThm; // may get invalid on external delete event + Glib::ustring fname; // must be saved separately + + rtengine::InitialImage* isrc; + rtengine::StagedImageProcessor* ipc; + rtengine::StagedImageProcessor* beforeIpc; // for the before-after view + + EditorPanelIdleHelper* epih; + + int err; + + time_t processingStartedTime; + + sigc::connection ShowHideSidePanelsconn; + + bool isProcessing; + + IdleRegister idle_register; }; #endif diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 8c7bae0fa..ed9b70e8d 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -22,12 +22,6 @@ #include "inspector.h" #include "placesbrowser.h" -int FilePanelInitUI (void* data) -{ - (static_cast(data))->init (); - return 0; -} - FilePanel::FilePanel () : parent(nullptr) { @@ -143,13 +137,21 @@ FilePanel::FilePanel () : parent(nullptr) fileCatalog->setFileSelectionChangeListener (tpc); fileCatalog->setFileSelectionListener (this); - add_idle (FilePanelInitUI, this); + + const auto func = [](gpointer data) -> gboolean { + static_cast(data)->init(); + return FALSE; + }; + + idle_register.add(func, this); show_all (); } FilePanel::~FilePanel () { + idle_register.destroy(); + rightNotebookSwitchConn.disconnect(); if (inspectorPanel) { diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h index 68f021043..d54f5f75a 100644 --- a/rtgui/filepanel.h +++ b/rtgui/filepanel.h @@ -33,38 +33,12 @@ #include "progressconnector.h" class RTWindow; -class FilePanel : public Gtk::HPaned, + +class FilePanel final : + public Gtk::HPaned, public FileSelectionListener, public PParamsChangeListener { - -protected: - //DirBrowser* dirBrowser; - PlacesBrowser* placesBrowser; - RecentBrowser* recentBrowser; - // FileCatalog* fileCatalog; // filecatalog is the file browser with the button bar above it - - Inspector* inspectorPanel; - Gtk::VPaned* tpcPaned; - BatchToolPanelCoordinator* tpc; - History* history; - //FilterPanel* filterPanel; - RTWindow* parent; - Gtk::Notebook* rightNotebook; - sigc::connection rightNotebookSwitchConn; - - struct pendingLoad { - bool complete; - ProgressConnector *pc; - Thumbnail *thm; - }; - MyMutex pendingLoadMutex; - std::vector pendingLoads; - - int error; - - void on_NB_switch_page(Gtk::Widget* page, guint page_num); - public: FilePanel (); ~FilePanel (); @@ -107,6 +81,32 @@ public: bool handleShortcutKey (GdkEventKey* event); void updateTPVScrollbar (bool hide); void updateTabsUsesIcons (bool useIcons); + +private: + void on_NB_switch_page(Gtk::Widget* page, guint page_num); + + PlacesBrowser* placesBrowser; + RecentBrowser* recentBrowser; + + Inspector* inspectorPanel; + Gtk::VPaned* tpcPaned; + BatchToolPanelCoordinator* tpc; + History* history; + RTWindow* parent; + Gtk::Notebook* rightNotebook; + sigc::connection rightNotebookSwitchConn; + + struct pendingLoad { + bool complete; + ProgressConnector *pc; + Thumbnail *thm; + }; + MyMutex pendingLoadMutex; + std::vector pendingLoads; + + int error; + + IdleRegister idle_register; }; #endif diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index 43bfc11b0..e8310ff0e 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -43,6 +43,53 @@ guint add_idle (GSourceFunc function, gpointer data) //gtk_main_iteration_do(false); } +IdleRegister::~IdleRegister() +{ + destroy(); +} + +void IdleRegister::add(GSourceFunc function, gpointer data) +{ + struct DataWrapper { + IdleRegister* const self; + GSourceFunc function; + gpointer data; + }; + + const auto dispatch = [](gpointer data) -> gboolean { + DataWrapper* const data_wrapper = static_cast(data); + + if (!data_wrapper->function(data_wrapper->data)) { + data_wrapper->self->mutex.lock(); + data_wrapper->self->ids.erase(data_wrapper); + data_wrapper->self->mutex.unlock(); + + delete data_wrapper; + return FALSE; + } + + return TRUE; + }; + + DataWrapper* const data_wrapper = new DataWrapper{ + this, + function, + data + }; + + mutex.lock(); + ids[data_wrapper] = add_idle(dispatch, data_wrapper); + mutex.unlock(); +} + +void IdleRegister::destroy() +{ + mutex.lock(); + for (const auto id : ids) { + g_source_remove(id.second); + } + mutex.unlock(); +} /* gboolean giveMeAGo(void* data) { diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index e5919c9e4..12370a571 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -19,13 +19,17 @@ #ifndef __GUI_UTILS_ #define __GUI_UTILS_ +#include + #include + #include -#include "../rtengine/rtengine.h" + #include "../rtengine/coord.h" +#include "../rtengine/noncopyable.h" +#include "../rtengine/rtengine.h" + #include "rtimage.h" -#include -#include Glib::ustring escapeHtmlChars(const Glib::ustring &src); bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference = true); @@ -40,6 +44,20 @@ void setExpandAlignProperties(Gtk::Widget *widget, bool hExpand, bool vExpand, e guint add_idle (GSourceFunc function, gpointer data); +class IdleRegister final : + public rtengine::NonCopyable +{ +public: + ~IdleRegister(); + + void add(GSourceFunc function, gpointer data); + void destroy(); + +private: + std::map ids; + MyMutex mutex; +}; + // TODO: The documentation says gdk_threads_enter and gdk_threads_leave should be replaced // by g_main_context_invoke(), g_idle_add() and related functions, but this will require more extensive changes. // We silence those warnings until then so that we notice the others. diff --git a/rtgui/history.cc b/rtgui/history.cc index 11f8c63a0..6c6d74643 100644 --- a/rtgui/history.cc +++ b/rtgui/history.cc @@ -26,14 +26,14 @@ using namespace rtengine::procparams; Glib::ustring eventDescrArray[NUMOFEVENTS]; -History::History (bool bookmarkSupport) : blistener(nullptr), tpc (nullptr), bmnum (1) +History::History (bool bookmarkSupport) : blistener (nullptr), tpc (nullptr), bmnum (1) { blistenerLock = false; // sets default that the Before preview will not be locked // fill history event message array for (int i = 0; i < NUMOFEVENTS; i++) { - eventDescrArray[i] = M(Glib::ustring::compose("HISTORY_MSG_%1", i + 1)); + eventDescrArray[i] = M (Glib::ustring::compose ("HISTORY_MSG_%1", i + 1)); } // History List @@ -41,7 +41,7 @@ History::History (bool bookmarkSupport) : blistener(nullptr), tpc (nullptr), bmn Gtk::ScrolledWindow* hscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); hscrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - Gtk::Frame* histFrame = Gtk::manage (new Gtk::Frame (M("HISTORY_LABEL"))); + Gtk::Frame* histFrame = Gtk::manage (new Gtk::Frame (M ("HISTORY_LABEL"))); histFrame->set_name ("HistoryPanel"); histFrame->add (*hscrollw); @@ -51,10 +51,10 @@ History::History (bool bookmarkSupport) : blistener(nullptr), tpc (nullptr), bmn historyModel = Gtk::ListStore::create (historyColumns); hTreeView->set_model (historyModel); hTreeView->set_headers_visible (false); - hTreeView->set_hscroll_policy(Gtk::SCROLL_MINIMUM); - hTreeView->set_vscroll_policy(Gtk::SCROLL_NATURAL); - hTreeView->set_size_request(80, -1); - hTreeView->set_resize_mode(Gtk::RESIZE_QUEUE); + hTreeView->set_hscroll_policy (Gtk::SCROLL_MINIMUM); + hTreeView->set_vscroll_policy (Gtk::SCROLL_NATURAL); + hTreeView->set_size_request (80, -1); + hTreeView->set_resize_mode (Gtk::RESIZE_QUEUE); Gtk::CellRendererText *changecrt = Gtk::manage (new Gtk::CellRendererText()); changecrt->property_ellipsize() = Pango::ELLIPSIZE_END; @@ -63,46 +63,46 @@ History::History (bool bookmarkSupport) : blistener(nullptr), tpc (nullptr), bmn Gtk::TreeView::Column *hviewcol = Gtk::manage (new Gtk::TreeView::Column ("")); hviewcol->pack_start (*changecrt, true); hviewcol->add_attribute (changecrt->property_markup (), historyColumns.text); - hviewcol->set_expand(true); + hviewcol->set_expand (true); hviewcol->set_resizable (true); - hviewcol->set_fixed_width(35); - hviewcol->set_min_width(35); - hviewcol->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE); + hviewcol->set_fixed_width (35); + hviewcol->set_min_width (35); + hviewcol->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); Gtk::TreeView::Column *hviewcol2 = Gtk::manage (new Gtk::TreeView::Column ("")); hviewcol2->pack_start (*valuecrt, true); hviewcol2->add_attribute (valuecrt->property_markup (), historyColumns.value); - hviewcol2->set_expand(true); - hviewcol2->set_resizable(true); - hviewcol2->set_fixed_width(35); - hviewcol2->set_min_width(35); - hviewcol2->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE); - valuecrt->set_alignment(1.f, 0.f); + hviewcol2->set_expand (true); + hviewcol2->set_resizable (true); + hviewcol2->set_fixed_width (35); + hviewcol2->set_min_width (35); + hviewcol2->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); + valuecrt->set_alignment (1.f, 0.f); - hTreeView->set_has_tooltip(true); - hTreeView->signal_query_tooltip().connect( sigc::mem_fun(*this, &History::on_query_tooltip) ); + hTreeView->set_has_tooltip (true); + hTreeView->signal_query_tooltip().connect ( sigc::mem_fun (*this, &History::on_query_tooltip) ); hTreeView->append_column (*hviewcol); hTreeView->append_column (*hviewcol2); - selchangehist = hTreeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &History::historySelectionChanged)); + selchangehist = hTreeView->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &History::historySelectionChanged)); // Bookmark List // ~~~~~~~~~~~~~ Gtk::HBox* ahbox = Gtk::manage (new Gtk::HBox ()); addBookmark = Gtk::manage (new Gtk::Button ()); // M("HISTORY_NEWSNAPSHOT") - setExpandAlignProperties(addBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + setExpandAlignProperties (addBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); //addBookmark->get_style_context()->set_junction_sides(Gtk::JUNCTION_RIGHT); - addBookmark->get_style_context()->add_class("Left"); - addBookmark->set_tooltip_markup (M("HISTORY_NEWSNAPSHOT_TOOLTIP")); + addBookmark->get_style_context()->add_class ("Left"); + addBookmark->set_tooltip_markup (M ("HISTORY_NEWSNAPSHOT_TOOLTIP")); Gtk::Image* addimg = Gtk::manage (new RTImage ("gtk-add.png")); addBookmark->set_image (*addimg); ahbox->pack_start (*addBookmark); delBookmark = Gtk::manage (new Gtk::Button ()); // M("HISTORY_DELSNAPSHOT") - setExpandAlignProperties(delBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + setExpandAlignProperties (delBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); //delBookmark->get_style_context()->set_junction_sides(Gtk::JUNCTION_LEFT); - delBookmark->get_style_context()->add_class("Right"); + delBookmark->get_style_context()->add_class ("Right"); Gtk::Image* delimg = Gtk::manage (new RTImage ("list-remove.png")); delBookmark->set_image (*delimg); ahbox->pack_start (*delBookmark); @@ -112,19 +112,19 @@ History::History (bool bookmarkSupport) : blistener(nullptr), tpc (nullptr), bmn bscrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); bscrollw->set_size_request (-1, 45); - Gtk::Frame* bmFrame = Gtk::manage (new Gtk::Frame (M("HISTORY_SNAPSHOTS"))); - bmFrame->set_name("Snapshots"); + Gtk::Frame* bmFrame = Gtk::manage (new Gtk::Frame (M ("HISTORY_SNAPSHOTS"))); + bmFrame->set_name ("Snapshots"); Gtk::VBox* bmBox = Gtk::manage (new Gtk::VBox ()); bmFrame->add (*bmBox); bmBox->pack_start (*bscrollw, Gtk::PACK_EXPAND_WIDGET, 4); bmBox->pack_end (*ahbox, Gtk::PACK_SHRINK, 4); - bmBox->set_size_request(-1,60); + bmBox->set_size_request (-1, 60); if (bookmarkSupport) { historyVPaned = Gtk::manage ( new Gtk::VPaned () ); historyVPaned->pack1 (*histFrame, true, true); historyVPaned->pack2 (*bmFrame, false, false); - pack_start(*historyVPaned); + pack_start (*historyVPaned); } else { pack_start (*histFrame); } @@ -136,19 +136,19 @@ History::History (bool bookmarkSupport) : blistener(nullptr), tpc (nullptr), bmn bookmarkModel = Gtk::ListStore::create (bookmarkColumns); bTreeView->set_model (bookmarkModel); bTreeView->set_headers_visible (false); - bTreeView->append_column_editable (M("HISTORY_SNAPSHOTS"), bookmarkColumns.text); + bTreeView->append_column_editable (M ("HISTORY_SNAPSHOTS"), bookmarkColumns.text); - selchangebm = bTreeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &History::bookmarkSelectionChanged)); + selchangebm = bTreeView->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &History::bookmarkSelectionChanged)); - addBookmark->signal_clicked().connect( sigc::mem_fun(*this, &History::addBookmarkPressed) ); - delBookmark->signal_clicked().connect( sigc::mem_fun(*this, &History::delBookmarkPressed) ); + addBookmark->signal_clicked().connect ( sigc::mem_fun (*this, &History::addBookmarkPressed) ); + delBookmark->signal_clicked().connect ( sigc::mem_fun (*this, &History::delBookmarkPressed) ); //hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_HORIZONTAL); hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_BOTH); //hTreeView->signal_size_allocate().connect( sigc::mem_fun(*this, &History::resized) ); - hTreeView->set_enable_search(false); - bTreeView->set_enable_search(false); + hTreeView->set_enable_search (false); + bTreeView->set_enable_search (false); show_all_children (); } @@ -156,7 +156,7 @@ History::History (bool bookmarkSupport) : blistener(nullptr), tpc (nullptr), bmn void History::initHistory () { - ConnectionBlocker selBlocker(selchangehist); + ConnectionBlocker selBlocker (selchangehist); historyModel->clear (); bookmarkModel->clear (); } @@ -182,8 +182,8 @@ void History::historySelectionChanged () if (row && tpc) { ProcParams pparams = row[historyColumns.params]; - ParamsEdited pe(true); - PartialProfile pp(&pparams, &pe); + ParamsEdited pe (true); + PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[historyColumns.paramsEdited]; tpc->profileChange (&pp, EvHistoryBrowsed, row[historyColumns.text], ¶msEdited); } @@ -215,8 +215,8 @@ void History::bookmarkSelectionChanged () if (row && tpc) { ProcParams pparams = row[bookmarkColumns.params]; - ParamsEdited pe(true); - PartialProfile pp(&pparams, &pe); + ParamsEdited pe (true); + PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[bookmarkColumns.paramsEdited]; tpc->profileChange (&pp, EvBookmarkSelected, row[bookmarkColumns.text], ¶msEdited); } @@ -262,36 +262,38 @@ void History::procParamsChanged (ProcParams* params, ProcEvent ev, Glib::ustring } // if there is no last item or its chev!=ev, create a new one - if (size == 0 || !row || row[historyColumns.chev] != ev || ev == EvProfileChanged) { - Gtk::TreeModel::Row newrow = *(historyModel->append()); - newrow[historyColumns.realText] = eventDescrArray[ev]; - newrow[historyColumns.text] = text; - newrow[historyColumns.value] = descr; - newrow[historyColumns.chev] = ev; - newrow[historyColumns.params] = *params; - newrow[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; + if (descr != "") { + if (size == 0 || !row || row[historyColumns.chev] != ev || ev == EvProfileChanged) { + Gtk::TreeModel::Row newrow = * (historyModel->append()); + newrow[historyColumns.realText] = eventDescrArray[ev]; + newrow[historyColumns.text] = text; + newrow[historyColumns.value] = descr; + newrow[historyColumns.chev] = ev; + newrow[historyColumns.params] = *params; + newrow[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; - if (ev != EvBookmarkSelected) { - selection->select (newrow); + if (ev != EvBookmarkSelected) { + selection->select (newrow); + } + + if (blistener && row && !blistenerLock) { + blistener->historyBeforeLineChanged (row[historyColumns.params]); + } else if (blistener && size == 0 && !blistenerLock) { + blistener->historyBeforeLineChanged (newrow[historyColumns.params]); + } } + // else just update it + else { + row[historyColumns.realText] = eventDescrArray[ev]; + row[historyColumns.text] = text; + row[historyColumns.value] = descr; + row[historyColumns.chev] = ev; + row[historyColumns.params] = *params; + row[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; - if (blistener && row && !blistenerLock) { - blistener->historyBeforeLineChanged (row[historyColumns.params]); - } else if (blistener && size == 0 && !blistenerLock) { - blistener->historyBeforeLineChanged (newrow[historyColumns.params]); - } - } - // else just update it - else { - row[historyColumns.realText] = eventDescrArray[ev]; - row[historyColumns.text] = text; - row[historyColumns.value] = descr; - row[historyColumns.chev] = ev; - row[historyColumns.params] = *params; - row[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; - - if (ev != EvBookmarkSelected) { - selection->select (row); + if (ev != EvBookmarkSelected) { + selection->select (row); + } } } @@ -322,7 +324,7 @@ void History::addBookmarkWithText (Glib::ustring text) } // append new row to bookmarks - Gtk::TreeModel::Row newrow = *(bookmarkModel->append()); + Gtk::TreeModel::Row newrow = * (bookmarkModel->append()); newrow[bookmarkColumns.text] = text; ProcParams params = row[historyColumns.params]; newrow[bookmarkColumns.params] = params; @@ -334,7 +336,7 @@ void History::addBookmarkPressed () { if (hTreeView->get_selection()->get_selected()) { - addBookmarkWithText (Glib::ustring::compose ("%1 %2", M("HISTORY_SNAPSHOT"), bmnum++)); + addBookmarkWithText (Glib::ustring::compose ("%1 %2", M ("HISTORY_SNAPSHOT"), bmnum++)); } } @@ -369,7 +371,7 @@ void History::undo () int size = historyModel->children().size (); if (size > 1) { - selection->select (historyModel->children().operator [](size - 2)); + selection->select (historyModel->children().operator [] (size - 2)); } } } @@ -390,7 +392,7 @@ void History::redo () int size = historyModel->children().size (); if (size > 1) { - selection->select (historyModel->children().operator [](size - 2)); + selection->select (historyModel->children().operator [] (size - 2)); } } } @@ -416,22 +418,24 @@ bool History::getBeforeLineParams (rtengine::procparams::ProcParams& params) return true; } -bool History::on_query_tooltip(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { +bool History::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) +{ bool displayTooltip = false; Gtk::TreeModel::Path path; int x2 = -1; int y2 = -1; - hTreeView->convert_widget_to_bin_window_coords(x, y, x2, y2); - bool hasPath = hTreeView->get_path_at_pos(x2, y2, path); + hTreeView->convert_widget_to_bin_window_coords (x, y, x2, y2); + bool hasPath = hTreeView->get_path_at_pos (x2, y2, path); if (hasPath) { if (path && !path.empty()) { - Gtk::TreeModel::iterator iter = historyModel->get_iter(path); + Gtk::TreeModel::iterator iter = historyModel->get_iter (path); + if (iter) { Glib::ustring param, val; - iter->get_value(1, param); - iter->get_value(2, val); + iter->get_value (1, param); + iter->get_value (2, val); /* * @@ -450,10 +454,11 @@ bool History::on_query_tooltip(int x, int y, bool keyboard_tooltip, const Glib:: tooltip->set_custom(*hbox); */ - tooltip->set_text(param+" : "+val); + tooltip->set_text (param + " : " + val); displayTooltip = true; } } } + return displayTooltip; } diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index f0f394e57..c5f7e46ff 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -1037,27 +1037,27 @@ bool Locallab::localretComputed_ () // printf("G2 anbspot=%i\n", anbspot->getValue()); if (listener) { //for all sliders - listener->panelChanged (Evlocallabanbspot, anbspot->getTextValue()); + listener->panelChanged (Evlocallabanbspot, "");//anbspot->getTextValue()); } if (listener) {//for curve - listener->panelChanged (EvlocallabCTgainCurverab, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabCTgainCurverab, M ("")); } if (listener) {//for curve - listener->panelChanged (EvlocallabCTgainCurve, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabCTgainCurve, M ("")); } if (listener) {//for curve - listener->panelChanged (Evlocallabllshape, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (Evlocallabllshape, M ("")); } if (listener) {//for curve - listener->panelChanged (Evlocallabccshape, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (Evlocallabccshape, M ("")); } if (listener) {//for curve - listener->panelChanged (EvlocallabLHshape, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabLHshape, M ("")); } @@ -1331,11 +1331,11 @@ bool Locallab::localComputed_ () //add events for each cases if (listener) { //for all sliders - listener->panelChanged (Evlocallabanbspot, anbspot->getTextValue()); + listener->panelChanged (Evlocallabanbspot, "");//anbspot->getTextValue()); } if (listener) {//for curve - listener->panelChanged (EvlocallabCTgainCurverab, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabCTgainCurverab, M ("")); } if (listener) {//for inverse color @@ -1375,19 +1375,19 @@ bool Locallab::localComputed_ () } if (listener) {//for curve reti - listener->panelChanged (EvlocallabCTgainCurve, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabCTgainCurve, M ("")); } if (listener) {//for curve LL - listener->panelChanged (Evlocallabllshape, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (Evlocallabllshape, M ("")); } if (listener) {//for curve LH - listener->panelChanged (EvlocallabLHshape, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabLHshape, M ("")); } if (listener) {//for curve LH - listener->panelChanged (Evlocallabccshape, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (Evlocallabccshape, M ("")); } return false; @@ -2000,7 +2000,7 @@ void Locallab::curveChanged (CurveEditor* ce) if (listener && getEnabled()) { if (ce == cTgainshape) { - listener->panelChanged (EvlocallabCTgainCurve, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabCTgainCurve, M ("HISTORY_CUSTOMCURVE"));//HISTORY_CUSTOMCURVE int strval = retrab->getValue(); //update MIP retrab->setValue (strval + 1); @@ -2012,9 +2012,9 @@ void Locallab::curveChanged (CurveEditor* ce) } else if (ce == cTgainshaperab) { - listener->panelChanged (EvlocallabCTgainCurverab, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabCTgainCurverab, M ("")); } else if (ce == LHshape) { - listener->panelChanged (EvlocallabLHshape, M ("HISTORY_CUSTOMCURVE")); + listener->panelChanged (EvlocallabLHshape, M ("")); int strval = retrab->getValue(); //update MIP retrab->setValue (strval + 1); @@ -2612,7 +2612,7 @@ void Locallab::adjusterChanged (Adjuster * a, double newval) } else if (a == sensih) { listener->panelChanged (Evlocallabsensih, sensih->getTextValue()); } else if (a == retrab) { - listener->panelChanged (Evlocallabretrab, retrab->getTextValue()); + listener->panelChanged (Evlocallabretrab, "");//retrab->getTextValue()); } else if (a == radius) { listener->panelChanged (Evlocallabradius, radius->getTextValue()); } else if (a == strength) { @@ -2638,7 +2638,7 @@ void Locallab::adjusterChanged (Adjuster * a, double newval) } else if (a == nbspot) { listener->panelChanged (Evlocallabnbspot, nbspot->getTextValue()); } else if (a == anbspot) { - listener->panelChanged (Evlocallabanbspot, anbspot->getTextValue()); + listener->panelChanged (Evlocallabanbspot, "");//anbspot->getTextValue()); } else if (a == vart) { listener->panelChanged (Evlocallabvart, vart->getTextValue()); } else if (a == chrrt) { diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 0504a3934..bf2d4ce67 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -118,7 +118,7 @@ Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), fals Resize::~Resize () { - + idle_register.destroy(); delete scale; delete sizeBox; } @@ -352,68 +352,76 @@ void Resize::sizeChanged (int mw, int mh, int ow, int oh) void Resize::setDimensions () { + const auto func = [](gpointer data) -> gboolean { + Resize* const self = static_cast(data); - int refw, refh; + self->wconn.block(true); + self->hconn.block(true); + self->scale->block(true); - wconn.block (true); - hconn.block (true); - scale->block(true); + int refw, refh; - if (appliesTo->get_active_row_number() == 0 && cropw) { - // Applies to Cropped area - refw = cropw; - refh = croph; - } else { - // Applies to Full image or crop is disabled - refw = maxw; - refh = maxh; - } - - GThreadLock lock; - w->set_range (32, 4 * refw); - h->set_range (32, 4 * refh); - - double tmpScale; - - switch (spec->get_active_row_number()) { - case (0): // Scale mode - w->set_value((double)((int)( (double)(refw) * scale->getValue() + 0.5) )); - h->set_value((double)((int)( (double)(refh) * scale->getValue() + 0.5) )); - break; - - case (1): // Width mode - tmpScale = w->get_value() / (double)refw; - scale->setValue (tmpScale); - h->set_value((double)((int)( (double)(refh) * tmpScale + 0.5) )); - break; - - case (2): // Height mode - tmpScale = h->get_value() / (double)refh; - scale->setValue (tmpScale); - w->set_value((double)((int)( (double)(refw) * tmpScale + 0.5) )); - break; - - case (3): { // Bounding box mode - double wSliderValue = w->get_value(); - double hSliderValue = h->get_value(); - - if ( (wSliderValue / hSliderValue) < ((double)refw / (double)refh)) { - tmpScale = wSliderValue / (double)refw; + if (self->appliesTo->get_active_row_number() == 0 && self->cropw) { + // Applies to Cropped area + refw = self->cropw; + refh = self->croph; } else { - tmpScale = hSliderValue / (double)refh; + // Applies to Full image or crop is disabled + refw = self->maxw; + refh = self->maxh; } - scale->setValue (tmpScale); - break; - } + self->w->set_range(32, 4 * refw); + self->h->set_range(32, 4 * refh); - default: - break; - } + switch (self->spec->get_active_row_number()) { + case 0: { + // Scale mode + self->w->set_value(static_cast(static_cast(static_cast(refw) * self->scale->getValue() + 0.5))); + self->h->set_value(static_cast(static_cast(static_cast(refh) * self->scale->getValue() + 0.5))); + break; + } - scale->block(false); - wconn.block (false); - hconn.block (false); + case 1: { + // Width mode + const double tmp_scale = self->w->get_value() / static_cast(refw); + self->scale->setValue(tmp_scale); + self->h->set_value(static_cast(static_cast(static_cast(refh) * tmp_scale + 0.5))); + break; + } + + case 2: { + // Height mode + const double tmp_scale = self->h->get_value() / static_cast(refh); + self->scale->setValue(tmp_scale); + self->w->set_value(static_cast(static_cast(static_cast(refw) * tmp_scale + 0.5))); + break; + } + + case 3: { + // Bounding box mode + const double tmp_scale = + self->w->get_value() / self->h->get_value() < static_cast(refw) / static_cast(refh) + ? self->w->get_value() / static_cast(refw) + : self->h->get_value() / static_cast(refh); + + self->scale->setValue(tmp_scale); + break; + } + + default: { + break; + } + } + + self->scale->block(false); + self->wconn.block(false); + self->hconn.block(false); + + return FALSE; + }; + + idle_register.add(func, this); } void Resize::fitBoxScale() diff --git a/rtgui/resize.h b/rtgui/resize.h index cf640c281..acba5b478 100644 --- a/rtgui/resize.h +++ b/rtgui/resize.h @@ -25,25 +25,13 @@ #include "toolpanel.h" #include "guiutils.h" -class Resize : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::SizeListener +class Resize final : + public ToolParamBlock, + public AdjusterListener, + public FoldableToolPanel, + public rtengine::SizeListener { - -protected: - Adjuster* scale; - Gtk::VBox* sizeBox; - MyComboBoxText* appliesTo; - MyComboBoxText* method; - MyComboBoxText* spec; - MySpinButton* w; - MySpinButton* h; - int maxw, maxh; - int cropw, croph; - sigc::connection sconn, aconn, wconn, hconn; - bool wDirty, hDirty; - ToolParamBlock* packBox; - public: - Resize (); ~Resize (); @@ -75,6 +63,20 @@ private: int getComputedHeight (); void notifyBBox (); void updateGUI (); + + Adjuster* scale; + Gtk::VBox* sizeBox; + MyComboBoxText* appliesTo; + MyComboBoxText* method; + MyComboBoxText* spec; + MySpinButton* w; + MySpinButton* h; + int maxw, maxh; + int cropw, croph; + sigc::connection sconn, aconn, wconn, hconn; + bool wDirty, hDirty; + ToolParamBlock* packBox; + IdleRegister idle_register; }; #endif