Author Topic: Change MText to a single color  (Read 11569 times)

0 Members and 1 Guest are viewing this topic.

LE

  • Guest
Change MText to a single color
« on: November 21, 2006, 07:20:03 PM »
Here is a way to change a MTEXT with different colors to a single one - in progress.

Code: [Select]
#include <vector>
#include <algorithm>
using namespace std;

typedef std::vector<CString> sList;
typedef std::vector<CString>::iterator sListIt;
sList list;
CString s;

Code: [Select]
int MTextEnumerator(AcDbMTextFragment *frag, void *param)
{
s = frag->text;
list.push_back(s);
return 1;
}

Code: [Select]
static void changeMtextColor (void)
{
Acad::ErrorStatus es;
ads_name ename;
ads_point pt;
if (acedEntSel(_T("\nSelect a MText: "), ename, pt) != RTNORM) return;
AcDbObjectId id = AcDbObjectId::kNull;
acdbGetObjectId(id, ename);
if (id == AcDbObjectId::kNull) return;
AcDbObjectPointer<AcDbMText> pObj(id, AcDb::kForWrite);
if ((es = pObj.openStatus()) != Acad::eOk)
{
if (es == Acad::eNotThatKindOfClass)
{
acutPrintf(_T("\nSelect a MText."));
} else {
acutPrintf(_T("\nError when opening the entity."));
}
return;
}
AcDbMText *pMText = AcDbMText::cast(pObj.object());
CString str = pMText->contents();
pMText->explodeFragments(MTextEnumerator, NULL);
CString snew;
sListIt it = list.begin();
while (it != list.end())
{
CString & nStr = *it;
//acutPrintf(_T("\n %s\n"), p);
snew += nStr; //+ _T(" ");
it++;
}
//acutPrintf(_T("\nSNEW: %s\n"), snew);
pMText->setContents(snew);
list.clear();
//acutPrintf(_T("%s\n"), str);
}
« Last Edit: November 24, 2006, 09:57:01 AM by LE »

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Change MText to a single color
« Reply #1 on: November 21, 2006, 07:50:17 PM »
Louis,

Is there any particular reason why you are doing this:
Code: [Select]
AcDbObjectPointer<AcDbMText> pObj(id, AcDb::kForWrite);

when there is a predefined typedef already available which better implies your intent:
Code: [Select]
AcDbEntityPointer<AcDbMText> pMT(id, AcDb::kForWrite);

The second is much better I think...clearer.

Also, once you have a smart pointer like this, you don't need to go on and do this:
Code: [Select]
AcDbMText *pMText = AcDbMText::cast(pObj.object());

That to me is redundant.
If it was me, I would do it like this:

Code: [Select]
#define AcDbEntityPointer<AcDbMText> AcDbMTextPointer; //somewhere at top of file
...
//Acquire objectid somehow...
...
AcDbMTextPointer pMt(id, AcDb::kForWrite);
Acad::ErrorStatus es = pMt.OpenStatus();
if (es != Acad::eOK)
  return;

CString str = pMt->contents();
etc. etc.

Just some thoughts - hope it helps.

Cheers,
Glenn.
Me

LE

  • Guest
Re: Change MText to a single color
« Reply #2 on: November 21, 2006, 10:18:19 PM »
Gracias, Glenn

I wrote that from memory .... Thanks!

I'm about to modified the code...

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Change MText to a single color
« Reply #3 on: November 21, 2006, 10:49:01 PM »
I wrote that from memory ....

So did I, so it might be slightly wrong, but I'm sure you get the idea.
Me

LE

  • Guest
Re: Change MText to a single color
« Reply #4 on: November 21, 2006, 10:54:45 PM »
Here is the (better) formatted code...  :-)

Code: [Select]
static void changeMtextColor (void)
{
ads_name ename;
ads_point pt;
if (acedEntSel(_T("\nSelect a MText: "), ename, pt) != RTNORM) return;
AcDbObjectId id = AcDbObjectId::kNull;
acdbGetObjectId(id, ename);
if (id == AcDbObjectId::kNull) return;
AcDbObjectPointer <AcDbMText> pMText (id, AcDb::kForWrite);
Acad::ErrorStatus es = pMText.openStatus();
if (es != Acad::eOk) return;
CString str = pMText->contents();
pMText->explodeFragments(MTextEnumerator, NULL);
CString snew;
sListIt it = list.begin();
while (it != list.end())
{
CString & nStr = *it;
snew += nStr;
it++;
}
pMText->setContents(snew);
list.clear();
}

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Change MText to a single color
« Reply #5 on: November 21, 2006, 11:20:27 PM »
Now you're cooking! Much better.  :-D
Me

LE

  • Guest
Re: Change MText to a single color
« Reply #6 on: November 22, 2006, 01:15:05 PM »
The command using C++ and ObjectARX

Code: [Select]
static void changeColorMText (const ads_name ename)
{
AcDbObjectId id = AcDbObjectId::kNull;
acdbGetObjectId(id, ename);
if (id == AcDbObjectId::kNull) return;
AcDbObjectPointer <AcDbMText> pMText (id, AcDb::kForWrite);
Acad::ErrorStatus es = pMText.openStatus();
if (es != Acad::eOk) return;
CString txtstr = pMText->contents();
int lth = txtstr.GetLength();
CString txt1 ("");
CString let ("");
int cont = 0, flag = 0;
for (int j = 0; j < lth; j++)
{
let = txtstr.Mid(cont, 1);
if (let == "\\")
{
// remove index or true and book colors
// in case any of them are first appended
if (txtstr.Mid((cont + 1), 1) == "C" || txtstr.Mid((cont + 1), 1) == "c")
{
int i = cont + 2;
while (txtstr.Mid(i, 1) != ";")
{
i = i + 1;
}
// remove true and book colors
if (txtstr.Mid((i + 1), 1) == "\\" && txtstr.Mid((i + 2), 1) == "c")
{
i = i + 2;
while (txtstr.Mid(i, 1) != ";")
{
i = i + 1;
}
}
txt1 = txt1 + txtstr.Mid((i + 1), 1);
cont = i + 2;
} else { 
flag = 1;
}
} else {
txt1 = txt1 + let;
cont = 1 + cont;
}
if (flag == 1)
{
txt1 = txt1 + let;
cont = 1 + cont;
flag = 0;
}
}
pMText->setContents(txt1);
}

Code: [Select]
static void removeColorsMTexts (void)
{
ads_name selSet, ename;
resbuf *rbFilter = acutBuildList(RTDXF0, _T("MTEXT"), RTNONE);
if (acedSSGet(NULL, NULL, NULL, rbFilter, selSet)!= RTNORM)
{
acutRelRb(rbFilter);
return;
}
acutRelRb(rbFilter);
long selLength = 0, i;
if (acedSSLength(selSet, &selLength) != RTNORM || selLength == 0)
{
acedSSFree(selSet);
return;
}
for (i = 0; i < selLength; i++)
{
acedSSName(selSet, i, ename);
changeColorMText(ename);
}
acedSSFree(selSet);
}
« Last Edit: November 24, 2006, 09:58:49 AM by LE »

LE

  • Guest
Re: Change MText to a single color
« Reply #7 on: November 22, 2006, 11:55:28 PM »
The command using C# - in progress.

Code: [Select]
        [CommandMethod("GetMText")]
        static public void readMTextContents()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = HostApplicationServices.WorkingDatabase;
            PromptEntityResult res = ed.GetEntity("\nSelect a MText: ");
            if (res.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DocumentLock doclock = acadApp.DocumentManager.MdiActiveDocument.LockDocument();
                DBObject obj = tr.GetObject(res.ObjectId, OpenMode.ForWrite, false);
                MText text = obj as MText;
                if (text == null) return;
                string strtext = text.Contents;

                tr.Commit();
            }
        }

I will try to implement, regular expressions.
« Last Edit: November 24, 2006, 10:00:36 AM by LE »

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Change MText to a single color
« Reply #8 on: November 23, 2006, 12:02:52 AM »
Luis,

You don't need to document lock as a command typically runs in the document context and Acad handles the locking automagically.
Other than that, it looks fine to me.

Cheers,
Glenn.

PS. Once you have the Document (doc) you can get the database from it: Database db = doc.Database
No need to use HostAplicationServices in this case.
Me

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Change MText to a single color
« Reply #9 on: November 23, 2006, 12:06:23 AM »
Also, you can shorten this:
Code: [Select]
DBObject obj = tr.GetObject(res.ObjectId, OpenMode.ForWrite, false);
MText text = obj as MText;

to this:
Code: [Select]
MText text = tr.GetObject(res.ObjectId, OpenMode.ForWrite, false) as MText;
if (text == null)
  return;

Cheers,
Glenn.
Me

LE

  • Guest
Re: Change MText to a single color
« Reply #10 on: November 23, 2006, 12:09:06 AM »
:-o

Thanks! - it makes more sense.... now, to the regular expressions... and see if I can bake something...  :roll:

LE

  • Guest
Re: Change MText to a single color
« Reply #11 on: November 23, 2006, 11:51:31 AM »
The command using lisp

- does not include the removal for the true and book colors - has the ability to apply the color to the MText.

Code: [Select]
(if (not acad_object)
  (setq acad_object (vlax-get-acad-object)))

(defun put-property  (vla-obj par-name par-value)
  (if (eq (type par-value) 'VARIANT)
    (if (> (vlax-variant-type par-value) 8192)
      (setq par-value (vlax-safearray->list
(vlax-variant-value par-value)))))

  (setq par-value (cond
    ((eq :vlax-false par-value) 0)
    ((eq :vlax-true par-value) -1)
    (t par-value)))

  (if (and (= (type vla-obj) 'VLA-OBJECT)
   (vlax-write-enabled-p vla-obj)
   (not (equal (vlax-get vla-obj par-name) par-value)))
    (vlax-put vla-obj par-name par-value)))

(defun mtext-onecolor
       (obj colornum /    txtstr   txt1
lth cont   let    i     flag
vla_truecolor)
  (if (eq (vla-get-objectname obj) "AcDbMText")
    (progn
      (setq txtstr (vla-get-textstring obj))
      (setq txt1 "")
      (setq lth (strlen txtstr))
      (setq cont 1)
      (repeat lth
(setq let (substr txtstr cont 1))
(if (= let "\\")
  (progn
    (if (= (substr txtstr (+ cont 1) 1) "C")
      (progn
(setq i (+ cont 2))
(while (/= (substr txtstr i 1) ";")
  (setq i (1+ i)))
(setq txt1
       (strcat txt1
       "\\C"
       (itoa colornum)
       ";"
       (substr txtstr (+ i 1) 1)))
(setq cont (+ i 2)))
      (setq flag t)))
  (progn
    (setq txt1 (strcat txt1 let))
    (setq cont (1+ cont))))

(if flag
  (progn
    (setq txt1 (strcat txt1 let))
    (setq cont (1+ cont))
    (setq flag nil))))

      (vla-put-textstring obj txt1)

      (if (wcmatch (getvar "acadver") "16*")
(setq vla_truecolor
       (vla-getinterfaceobject
acad_object
"AutoCAD.AcCmColor.16")))

      (if (wcmatch (getvar "acadver") "16*")
(progn

  (vla-put-colorindex
    vla_truecolor
    global_color_use)

  (if obj
    (vla-put-truecolor obj vla_truecolor)))

(if (wcmatch (getvar "acadver") "15*")
  (put-property obj 'color global_color_use)))

      (vla-update obj))))
« Last Edit: November 24, 2006, 09:55:14 AM by LE »

LE

  • Guest
Re: Change MText to a single color
« Reply #12 on: November 23, 2006, 07:48:31 PM »
The command in C# - Using Regular Expressions

Notes:
1. The command is per single MTEXT selection.
2. Does not remove the formatted blocks "{" and "}" - it does not hurt to leave them as part of the Contents.


Code: [Select]
using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Globalization;

Code: [Select]
[CommandMethod("CHMTextColor")]
static public void readMTextContents()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    PromptEntityResult res = ed.GetEntity("\nSelect a MText: ");
    if (res.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        MText text = tr.GetObject(res.ObjectId, OpenMode.ForWrite, false) as MText;
        if (text == null) return;
        string strtext = text.Contents;
        Regex r = new Regex(@"\\[^;]*\w\W");
        string s = "";
        foreach (string subString in r.Split(strtext))
        {
            s += subString;
        }
        text.Contents = s;
        tr.Commit();
    }
« Last Edit: November 24, 2006, 09:53:41 AM by LE »

LE

  • Guest
Re: Change MText to a single color
« Reply #13 on: November 24, 2006, 09:21:35 PM »
Adding a user interface using C# - with new features to edit an mtext - in progress - (I been doing this project - just as an exercise, does not mean to be completed or to trying to reinvent the wheel or to replace anything).

Code: [Select]
        [CommandMethod("MTEXTEDITOR")]
        static public void test()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            PromptEntityResult res = ed.GetEntity("\nSelect a MText: ");
            if (res.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                MText text = tr.GetObject(res.ObjectId, OpenMode.ForWrite, false) as MText;
                if (text == null) return;
                //string strtext = text.Contents;

                using (MTextForm form = new MTextForm())
                {
                    form.Contents = text.Contents;
                    acadApp.ShowModalDialog(form);
                    text.Contents = form.Contents;
                }

                // first archaic approach of filling the textbox
                // with the string
                //this.textBox1.Text = strtext;

                // option to remove color formatting - still are kept the {}
                //Regex r = new Regex(@"\\[^;]*\w\W");
                //string s = "";
                //foreach (string subString in r.Split(strtext))
                //{
                //    s += subString;
                //}
                //text.Contents = s; // mtext update without color's

                tr.Commit();
            }

            // first approach
            //MTextForm modalForm = new MTextForm();
            //modalForm.ShowDialog();
        }

        public string Contents
        {
            get { return this.textBox1.Text; }
            set { this.textBox1.Text = value; }
        }

LE

  • Guest
Re: Change MText to a single color
« Reply #14 on: November 27, 2006, 12:29:50 PM »
Regex r = new Regex(@"\\[^;]*\w\W");

No idea if anyone have tested the above, but does not work as spected, it requires a better pattern, anyway it was my first time trying to implement regular expression in C#