[V8i MDL C++] Getting a BSIColorDescr from an element colour

I need to get a BSIColorDescr for a given element colour. If the element colour is 0-256 then this is trivial with mdlColorPal_getElemColorDescrByModelRef(), but of course MicroStation allows the symbology colour to be any RGB colour these days, and this function won't work with colours above 256. 

To achieve 24-bit colours, it seems MicroStation uses some internal colour map that stores these RGB colours as required. For example, creating a new shade of mauve from the colour swatch might assign an element colour of 780.

Now I can easily get the RGB of this value using mdlColor_elementColorToRGB(); however I don't know how to get the corresponding BSIColorDescr from this RGB. There must be some hidden colour table that MicroStation keeps of all of these assigned colours (above 256) within the DGN file, but I can't see any such table exposed in the SDK.

Since the BSIColorDescr is opaque, I can't allocate one for myself on the fly as required, as these pointers usually refer back to a colour table. The colour table APIs all expect a 256 entry colour table, so I can't really use these, and I won't know in advance how many of these allocated colours are in use in any model, since this is also missing from the SDK.

So how do I get a persistent BSIColorDescr pointer for any arbitrary RGB colour used in a model? It really seems the SDK is sorely lacking in exposing this to the programmer. If I want to display one of these colours in a dialog, then I need a persistent BSIColorDescrP for every arbitrary colour defined beyond the attached colour table.

Cheers.

Parents
  • Hello Piers,
    Just finding mdlColorDescr_setByRgb function. Is it appropriate for your desire ?



  • Some responses to the above:

    Unknown said:
    Hello Piers,

    Just finding mdlColorDescr_setByRgb function. Is it appropriate for your desire ?

    Yongan, yes this does work as I stated earlier, but doesn't answer my main question or problem. To quote myself above:

    Unknown said:

     I can certainly set a BSIColorDescr with the correct RGB values, but where do I get one in the first place? Being an opaque pointer (i.e. defined as void), I can't allocate one since I can't do sizeof(). I can grab one from the attached colour table, but screwing with it will permanently change the colour table display (but not the value) until I restart MicroStation.

    Unknown said:

    any element color is stored as UInt32 (4 bytes) type in DGN V8 format:

    You're probably right Jan, there is a definition for IntColorDef in mstnviewport.h:

    union IntColorDef
    {
    RGBColorDef m_rgb;
    RGBAColorDef m_rgba;
    UInt32 m_int;
    };

    However, this union is not supported by all (many?) MDL functions, as evidenced by the fact that many fail for UInt32 values > 256.

    What is really needed is for someone internal at Bentley to step in and explain how we are meant to deal with a BSIColorDescr for values not in the attached colour table. It really makes no sense for me to allocate my own palette on the fly when I don't know in advance how many of these special colours are in the model, nor how big the BSIColorDescr is in the first place. Keeping this pointer opaque seems ridiculous when the functions to work with it are missing. 

    --
    Piers Porter
    Altiva Software

  • BSIColorDescr and BSIColorPalette are legacy concepts from the days before 32 bit displays. BSIColorDescr remains for use with some gui items. For example mdlTreeCell_getColorDescr.

    There isn't any "table" of BSIColorDescrs for element colors managed by MicroStation. mdlColorPal_getElemColorDescrByModelRef seems to return a BSIColorDescr that you don't have to free, but it's not actually a "real" BSIColorDescr, it's just something that can be treated as one to keep legacy api happy. But you are correct, we don't provide a way for you to create a BSIColorDescr yourself...

    What exactly do you need a BSIColorDescr for, because other than some gui controls that provide "get" functions to access the item's BSIColorDescr pointer (and manage it's memory!), they are best avoided.

    -B



  • Hi Brien, thanks for your reply.

    I am only using a BSIColorDescr because it's the only way I can see to create a symbology preview in a list model. I want to show the colour of design elements in a report, as shown in the attached screenshot below. 

    I do this by creating a ListModel with both text and icons, The code I use currently is a bit like this:


    lIcon = ICONID_ColorBoundary;
    if ( ( iColour >= 0 ) && iColour < 256 )
    {
        if ( ( mdlColorPal_getElemColorDescrByModelRef ( &fgColourDSP, iColour, modelRef, 0 ) == BSISUCCESS ) &&
             ( mdlColorPal_getElemColorDescrByModelRef ( &bgColourDSP, 255, modelRef, 0 ) == BSISUCCESS ) )
        {
            mdlListCell_setIconColorOverrides ( listCellSP, fgColourDSP, bgColourDSP );
        }
    }
    else if ( iColour >= 256 )
    {
        ... // What to do?
    }


    This creates an icon preview for the colour in my ListModel, but it doesn't work for 24-bit colours. In the screenshot above I have just inserted the generic colour swatch icon (ICONID_TrueColorTabIcon) to indicate that the last row is a 24-bit RGB value, but it would be more useful to show the actual colour used. It looks like there are icons to allow this, e.g. ICONID_ColorPatch12Pt if you had a BSIColorDescr set up with the correct colour.

    If there is some way to specify colours without resorting to using a BSIColorDescr then I am happy to do so, but it looks like this is a limitation imposed upon the public MDL SDK.

    --
    Piers Porter
    Altiva Software

  • This isn't really my area, but it would seem like you could do the following:

        BSIColorDescr* fgColor = nullptr;
        if (SUCCESS == mdlListCell_getIconColorOverrides(pCell, &fgColor, nullptr) && (nullptr != fgColor)) // <- I suspect this probably comes back with nullptr though...
            {
            RgbColorDef rgb;
    
            rgb.red = 0x7f; rgb.green = 0x7f; rgb.blue = 0;
            mdlColorDescr_setByRgb(fgColor, &rgb, 0);
            }

    Use the method below from DgnColorMap to get the element color information...

    //! Get the color information from the supplied element color id.
    //! @param[out] colorDef IntColorDef for the supplied element color, can be used to get TBGR or RGB color values.
    //! @param[out] colorIndex The 0 to INDEX_Background index into the file's DgnColorMap. For rgb and book colors this is the closest match from when they were created.
    //! @param[out] isTrueColor True if supplied element color is a rgb or book color, false for color index.
    //! @param[out] bookName Color book name for the supplied element color (empty string for rgb and indexed colors).
    //! @param[out] colorName Color name from color book for the supplied element color (empty string for rgb and indexed colors).
    //! @param[in] elementColor The element color to extract the information for.
    //! @param[in] dgnFile The file for the supplied element color.
    //! @return SUCCESS if element color is a valid rgb, book, or DgnColorMap index.
    //! COLOR_BYLEVEL or COLOR_BYCELL will return ERROR.
    static DGNPLATFORM_EXPORT StatusInt ExtractElementColorInfo (IntColorDef* colorDef, UInt32* colorIndex, bool* isTrueColor, WStringP bookName, WStringP colorName, UInt32 elementColor, DgnFileR dgnFile);

    Worst case scenario, include these locally (I don't think you'll need to call destroy, the list cell should take care of that).

    MSCORE_EXPORT int mdlColorDescr_create (BSIColorDescr **newDescrPP);

    MSCORE_EXPORT int mdlColorDescr_destroy (BSIColorDescr **colorDescrPP);

    HTH



    Answer Verified By: Piers Porter 

  • Reply
    • This isn't really my area, but it would seem like you could do the following:

          BSIColorDescr* fgColor = nullptr;
          if (SUCCESS == mdlListCell_getIconColorOverrides(pCell, &fgColor, nullptr) && (nullptr != fgColor)) // <- I suspect this probably comes back with nullptr though...
              {
              RgbColorDef rgb;
      
              rgb.red = 0x7f; rgb.green = 0x7f; rgb.blue = 0;
              mdlColorDescr_setByRgb(fgColor, &rgb, 0);
              }

      Use the method below from DgnColorMap to get the element color information...

      //! Get the color information from the supplied element color id.
      //! @param[out] colorDef IntColorDef for the supplied element color, can be used to get TBGR or RGB color values.
      //! @param[out] colorIndex The 0 to INDEX_Background index into the file's DgnColorMap. For rgb and book colors this is the closest match from when they were created.
      //! @param[out] isTrueColor True if supplied element color is a rgb or book color, false for color index.
      //! @param[out] bookName Color book name for the supplied element color (empty string for rgb and indexed colors).
      //! @param[out] colorName Color name from color book for the supplied element color (empty string for rgb and indexed colors).
      //! @param[in] elementColor The element color to extract the information for.
      //! @param[in] dgnFile The file for the supplied element color.
      //! @return SUCCESS if element color is a valid rgb, book, or DgnColorMap index.
      //! COLOR_BYLEVEL or COLOR_BYCELL will return ERROR.
      static DGNPLATFORM_EXPORT StatusInt ExtractElementColorInfo (IntColorDef* colorDef, UInt32* colorIndex, bool* isTrueColor, WStringP bookName, WStringP colorName, UInt32 elementColor, DgnFileR dgnFile);

      Worst case scenario, include these locally (I don't think you'll need to call destroy, the list cell should take care of that).

      MSCORE_EXPORT int mdlColorDescr_create (BSIColorDescr **newDescrPP);

      MSCORE_EXPORT int mdlColorDescr_destroy (BSIColorDescr **colorDescrPP);

      HTH



      Answer Verified By: Piers Porter 

    Children
    • Thanks Brien, that worked perfectly!

      You were right that mdlListCell_getIconColorOverrides() returned a NULL foreground colour, however using mdlColorDescr_create() I was able to create my own colour descriptor and apply it to the ListCell.

      For anyone else looking to build a ListModel containing colours, I used these functions:

      1. mdlColor_elementColorToRGB();
      2. mdlColorDescr_create();
      3. mdlColorDescr_setByRgb();
      4. mdlListCell_setIconColorOverrides();

      Using these you can create a colour patch using:

      • ICONID_ColorBoundary for colours 0-255,
      • ICONID_ColorPatchByLevel12Pt and ICONID_ColorPatchByCell12Pt for ByLevel and ByCell values, and
      • ICONID_ColorPatchByTrueColor12Pt for values > 256.

      The results are shown in the third column of the ListModel image below:

      --
      Piers Porter
      Altiva Software