Hvorfor Ubuntu (Studio)

Årsaken er RAD Studio fra Embarcadero! What????

Jeg bruker RAD Studio som mitt favoritt utviklings verktøy, og programmerer i C++. RAD Studio er, etter min mening, et av de beste utviklingsverktøy på markedet. Du programmerer ett sted, og lager programmer for både Windows, Apple maskiner, Android og Linux.

Selve RAD Studio mener jeg er skrevet i (Delphi-) Pascal. Delphi kommer fra gamle Borland. Borland var opprinnelig kjent for sin gamle C++ kompiler og OWL biblioteket. De regjerte nesten fullstendig den gangen. Så prøvde de seg med C++ Builder, Java Builder og Delphi Pascal. Det er antagelig mest riktig å si bare «Delphi» og ikke «Delphi Pascal». Delphi er en objekt orientert utgave av Pascal.

Alt det som er nevnt ovenfor er mer eller mindre skrevet i Delphi, hele det som nå kalles RAD Studio. RAD Studio inneholder nå både C++ Builder og Delphi, men ikke Java Builder (vet ikke om den fortsatt eksisterer).

Ok, tilbake til Ubuntu, som er en Linux distro. Jeg nevnte du kan sitte på en Windows maskin og lage programmer for Windows , Apple maskiner, Android og Linux, men det er visse begrensninger. Det gjelder C++.

Disse gutta er noen av verdens beste Pascal og Delphi programmerere, det skal de ha. Delphi er derfor deres førstefødte, som vi sier. Alt nytt kommer først til Delphi, deretter etter en viss tid til C++ Builder. Dette må vi godta.

Det betyr at RAD Studio ikke har ferdig alle funksjonene. De har f.eks. ferdig Delphi for Linux, men ikke C++ Builder, og den Linux distroen de har valgt å starte med, er Ubuntu.

En annen og lignende begrensning er det for Android. Google forlanger nå 64-bits kode i programmet. Det har de også ferdig for Delphi, men ikke for C++ Builder.

Da ser du mitt dilemma. Jeg kjenner litt til OpenSUSE distroen, og det er først nå jeg prøver Ubuntu, men den er jeg altså nå nødt til å kjøre. I tillegg må jeg altså bruke Delphi (Pascal) som programmerings verktøy foreløpig.

Embarcadero vil ikke si når C++ Builder får 64-bits kode for Android og når vi får C++ Builder for linux. De vil heller ikke bekrefte om det kommer til å skje. Det skjærer dypt i en hardcore C++ programmerers hjerte å skulle gå over til Delphi (Pascal) 🙂 men vi får leve i håpet. Jeg ser det som en umulighet at ikke vi skal få 64-bits C++ for Android og C++ for Linux.

Forskjell på GCC og G++

I dag lærte jeg faktisk noe nytt om kompilatorene GCC og G++ under Linux. Jeg har lekt med OpenSuse tidligere, laget enkle programmer osv. men stort set brukt QT eller et eller annet IDE system. Nå har jeg av spesielle grunner tenkt å kjøre Ubuntu, og da datt jeg borti installasjon av både GCC og g++.

Aldri tenkt over det tidligere, men hva er forskjellen?

GCC betyr GNU Compiler Collection, noen kaller den også GNU C Compiler. Du vet at det er forskjell på C og C++? OK, GCC er en samling kompilatorer, C, C++, Fortran, osv. Dvs at bruker du denne, vil den kompilere kildekode med etternavnet «.C» som «C»-kode og «.CPP» som C++ kode.

G++ derimot vil kompilere både «.C» og «.CPP» som C-kode. Desstuten vil G++, om du bruker den for å linke objekt filene, vil den automatisk linke inn «std» (Standard Library) C++ biblioteket. GCC gjør ikke dette.

Mao, GCC og G++ er vel to frontends til den samme kompilatoren, kan vi vel si.

Interessant, har aldri tenkt over dette tidligere. Nå bør jeg kanskje begynne å bruke «.cpp» som etternavn på kildekoden min når jeg mener c++?

Open SUSE og Ubuntu

Jeg driver og ser litt på et par Linux distribusjoner, Open SUSE og Ubuntu. Da går det fort et par dager uten nye poster her.

Jeg tenkte å prøve Delphi under Linux, men da må jeg forlate min kjære C++ og gå over til Delphi Pascal. Som gammel hardcore C++ programmerer skjærer det meg i hjertet å skulle bruke Pascal 🙂 Men tiden får vise.

I tillegg må jeg forlate min favoritt-distro, Open SUSE, og starte opp med Ubuntu. Delphi supporterer Ubuntu, men ikke Open SUSE.

Kanskje blir det litt QT i stedet, hvem vet?

Stiler, Styles

Jeg har lagt ut et lite eksemplel på hvordan du kan laste opp en stil ved runtime. Egentlig hadde jeg tenkt å bruke en INI-fil, men vi får se om jeg får tid og lyst til å gjøre det (skuffelsen med Firemonkey grafikk bibliotek som jeg nevnte 🙂 )

Siden med innlegget ligger her:

Eksempler->RAD Code Samples->Stiler, Styles

Edit Undo

Jeg har lagt ut en ny side med info om min løsning på en edit-undo. Dette løste jeg ved å opprette en «Stack» i dokument-klassen og rett og slett «stacke» den originale bitmapen.

Den er foreløpig i testversjon, men prinsippet ser ut til å virke 🙂

Siden ligger her:

Nytt C++ Eksempel

Har nettopp lagt ut et nytt eksempel vedr. gråtone bilde eller monochrome som Firemonkey kaller det.

Det er mye likt det som er skrevet i bloggen, men jeg synes det blir litt bedre strukturert i meny-sidene.

En annen forskjell (jeg KAN ta feil her) er at i sideoppsettet er det intet oppsett for f.eks. stikkord. Tar jeg feil her? Derfor nevner jeg noen av de nye sidene i bloggpost slik som her 🙂

Den nye siden finnes her:

Eksempler->RAD CodeSamples->Gråskala(Monochrome)

Firemonkey Gråskala

Som en slags avslutning på klagen på Firemonkey ImageLibrary kan jeg jo vise hvordan vi gjør om et RGB til Gråskala i Firemonkey. Det begynner på vanlig måte i hoveddelen med å kaste om på en adresse:

void __fastcall TForm1::menu_IMAGE_GRAYSCALE_Click(TObject *Sender)
{
	if (TabControl1->TabCount < 1 ) {
		return;
	}
	 TTabItem   *myTabItemPtr;

	 // Get a pointer to active tab

	 myTabItemPtr = TabControl1->ActiveTab;

	 // Type cast to class DocPage and
	 // let DocPage do the job
	 ((DocPage *) myTabItemPtr)->Monochrome();

}

Ikke mye hokus pokus i funksjonen ovenfor, men så fortsetter det i dokumentklassen:

// --------------------------------------------------------------------------
//  				Monochrome
// --------------------------------------------------------------------------

void __fastcall DocPage::Monochrome()
{
	try
	{
		TForm14 *dlgMonochrome =  new TForm14(Application);

		dlgMonochrome->Image1->Bitmap = Image1->Bitmap;
		dlgMonochrome->Caption = _T("Monochrome");

		dlgMonochrome->myMonochrome->Input = dlgMonochrome->Image1->Bitmap;
		//dlgBoxBlur->myBoxBlur->BlurAmount = dlgBoxBlur->TrackBar1->Value / 100;
		dlgMonochrome->Image2->Bitmap = dlgMonochrome->myMonochrome->Output;


		dlgMonochrome->ShowModal();
		if( dlgMonochrome -> iretState == 1 ) {

			// Don't forget the undo-stack

			UndoItem = new TUndoItem();
			UndoItem->UndoName = new String("Monochrome");
			UndoItem->UndoBitmap = new TBitmap();

			// Have to use "Assign()" because everything are pointers!!!

			UndoItem->UndoBitmap->Assign(Image1->Bitmap);
			mystack.push(UndoItem);

			Image1->Bitmap->Assign(dlgMonochrome->Image2->Bitmap);
			//Image1->Bitmap->Monochrome = true;

		}

		dlgMonochrome->DisposeOf();
	}
	catch(...)
	{
		ShowMessage("Monochrome did not succeed");
	}

}

Koden ovenfor viser min måte å lage en dialogboks på, en TForm klasse og så kjøres det en «dlgMonochrome->ShowModal()».

I de fleste av mine filteroperasjoner bruker jeg en dialogboks med to «TImage»-klasser, en for originalen og en for sluttresultatet. Bildet nedenfor viser det ved designtidspunkt i RAD-Studio

Koden for selve TForm-klassen er vist nedenfor.

//---------------------------------------------------------------------------

#ifndef MonochromeH
#define MonochromeH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>
#include <FMX.Effects.hpp>
#include <FMX.Filter.Effects.hpp>
#include <FMX.Objects.hpp>
//---------------------------------------------------------------------------
class TForm14 : public TForm
{
__published:	// IDE-managed Components
	TImage *Image1;
	TImage *Image2;
	TButton *Cancel;
	TButton *OK;
	void __fastcall OnCreate(TObject *Sender);
	void __fastcall CancelClick(TObject *Sender);
	void __fastcall OKClick(TObject *Sender);
private:	// User declarations
public:		// User declarations
	int iretState;
	TFilterMonochrome * myMonochrome;
	__fastcall TForm14(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm14 *Form14;
//---------------------------------------------------------------------------
#endif

De enkelte funksjonene i klassen ovenfor er det heller ikke mye å si om, de vises nedenfor:

//---------------------------------------------------------------------------

#include <fmx.h>
#pragma hdrstop

#include "Monochrome.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm14 *Form14;
//---------------------------------------------------------------------------
__fastcall TForm14::TForm14(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm14::OnCreate(TObject *Sender)
{
	myMonochrome = new TFilterMonochrome(this);

	 myMonochrome->Input = Image1->Bitmap;
	 //TrackBar1->Value = 25;
	 //myPixelate->BlockCount = TrackBar1->Value;
	 Image2->Bitmap = myMonochrome->Output;

}
//---------------------------------------------------------------------------
void __fastcall TForm14::CancelClick(TObject *Sender)
{
	iretState = 0;
	Close();

}
//---------------------------------------------------------------------------
void __fastcall TForm14::OKClick(TObject *Sender)
{
	iretState = 1;
	Close();

}
//---------------------------------------------------------------------------

Jeg konstruerer et monokrom filter ved inngangen, og så kan du se jeg kobler outputen fra filteret til inputen i Image2. til sist setter jeg en returstatus ved exit tidspunkt.

Kjøring av programmet ser slik ut:

Firemonkey Image Library 2

Først: Det hele starter i Hovedformen, «TForm1», alle menyfunksjoner gjør det, og så jumper programmet i de fleste tilfelle til en funksjon i «DocPage» klassen. Det eneste som gjøres her er å opprette en adressepeker til neste funksjon:

// --------------------- Display Image Properties ---------------

	void __fastcall TForm1::menu_PROPERTIES_Click(TObject *Sender)         // 19
{
	 TTabItem   *myTabItemPtr;

	 // Get a pointer to active tab
	 myTabItemPtr = TabControl1->ActiveTab;

	 // Type cast to class DocPage and
	 // let DocPage do the job
	 ((DocPage *) myTabItemPtr)->ImageProperties();
}

De meste av info finnes i bitmap’en, «TBitmap», og hvordan du henter opp denne er egentlig forklart i dokumentasjonen fra Embarcadero.

// --------------------------------------------------------------------------
//  				Image Properties
// --------------------------------------------------------------------------
void __fastcall DocPage::ImageProperties()
{
	try
	{
		TForm6 *dlgProperties =  new TForm6(Application);

		dlgProperties->Image1->Bitmap = Image1->Bitmap;
		dlgProperties->Caption = _T("Image Properties");

		// Pixelformat
		TPixelFormat myPixelformat = Image1->Bitmap->PixelFormat;
		UnicodeString strPixelformat(PixelFormatToString(myPixelformat));
		dlgProperties->Edit1->Text = strPixelformat;

		// Bitmap Scale
		float BitmapScale = Image1->Bitmap->BitmapScale;
		UnicodeString strBitmapScale(BitmapScale);
		dlgProperties->Edit2->Text = strBitmapScale;

		// Bytes per line
		int BytesPerLine = Image1->Bitmap->BytesPerLine;
		UnicodeString strBytesPerLine(BytesPerLine);
		dlgProperties->Edit3->Text = strBytesPerLine;

		// Bytes per pixel
		int BytesPerPixel = Image1->Bitmap->BytesPerPixel;
		UnicodeString strBytesPerPixel(BytesPerPixel);
		dlgProperties->Edit4->Text = strBytesPerPixel;

		// Bitmap Height
		int Height = Image1->Bitmap->Height;
		UnicodeString strHeight(Height);
		dlgProperties->Edit5->Text = strHeight;

		// Bitmap Width
		int Width = Image1->Bitmap->Width;
		UnicodeString strWidth(Width);
		dlgProperties->Edit6->Text = strWidth;
		// -----------------------------------------------------------------
		// DisplayCount
		iDisplayCount = Screen->DisplayCount;
		UnicodeString strDisplayCount(iDisplayCount);
		dlgProperties->Edit7->Text = strDisplayCount;

		// Desktop Width i pixels (might be for instance dual screen)
		iDesktopWidthInPixels = Screen->DesktopWidth;
		UnicodeString strDesktopWidth(iDesktopWidthInPixels);
		dlgProperties->Edit8->Text = strDesktopWidth;

		// Desktop Height i pixels
		iDesktopHeightInPixels = Screen->DesktopHeight;
		UnicodeString strDesktopHeight(iDesktopHeightInPixels);
		dlgProperties->Edit9->Text = strDesktopHeight;

		// Screen Width in pixels
		iScreenWidthInPixels = Screen->Width;
		UnicodeString strScreenWidth(iScreenWidthInPixels);
		dlgProperties->Edit10->Text = strScreenWidth;

		// Screen Height in pixels
		iScreenHeightInPixels = Screen->Height;
		UnicodeString strScreenHeight(iScreenHeightInPixels);
		dlgProperties->Edit11->Text = strScreenHeight;

		// Work area
		iWorkAreaWidthInPixels = Screen->WorkAreaWidth;
		UnicodeString strWorkAreaWidth(iWorkAreaWidthInPixels);
		dlgProperties->Edit12->Text = strWorkAreaWidth;

		iWorkAreaHeightInPixels = Screen->WorkAreaHeight;
		UnicodeString strWorkAreaHeight(iWorkAreaHeightInPixels);
		dlgProperties->Edit13->Text = strWorkAreaHeight;

		// Junior school math: a**2 + b**2 = c**2
		iScreenSizeInPixels = sqrt(iScreenWidthInPixels*iScreenWidthInPixels + iScreenHeightInPixels*iScreenHeightInPixels);
		UnicodeString strpixsize(iScreenSizeInPixels);
		dlgProperties->Edit14->Text = strpixsize;

        // Guessing 27" monitor as a starter
		iScreenPPI = iScreenSizeInPixels / 27;
		dlgProperties->Edit15->Text = iScreenPPI;

		//UnicodeString strii(17);

		dlgProperties->ComboBox1->Items->Add( 15);
		dlgProperties->ComboBox1->Items->Add( 17);
		dlgProperties->ComboBox1->Items->Add( 19);
		dlgProperties->ComboBox1->Items->Add( 20);
		dlgProperties->ComboBox1->Items->Add( 22);
		dlgProperties->ComboBox1->Items->Add( 24);
		dlgProperties->ComboBox1->Items->Add( 27);
		dlgProperties->ComboBox1->Items->Add( 28);
		dlgProperties->ComboBox1->Items->Add( 32);
		dlgProperties->ComboBox1->Items->Add( 34);
		dlgProperties->ComboBox1->Items->Add( 35);
		dlgProperties->ComboBox1->Items->Add( 43);
		dlgProperties->ComboBox1->Items->Add( 49);

		dlgProperties->ComboBox1->ItemIndex = 6;

		dlgProperties->ShowModal();
		if( dlgProperties -> iretState == 1 ) {

			//
		}

		dlgProperties->DisposeOf();
	}
	catch(...)
	{
		ShowMessage("Image properties did not succeed");
	}

}

Det som ligger av kode i selve dialogboksen, er å foreta en beregning hver gang du endrer skjermstørrelse. Da beregnes verdien av pixels/inch.

//---------------------------------------------------------------------------

void __fastcall TForm6::OnComboBoxChange(TObject *Sender)
{

	UnicodeString strSelected = ComboBox1->Selected->Text;
	int isize = strSelected.ToInt();
	UnicodeString scrSize = Edit14->Text;
	int iscrSize = scrSize.ToInt();
	int iPixPerInch = round(iscrSize / isize);

	Edit15->Text = iPixPerInch;
}

Firemonkey Image Library 1

Jeg har klaget mye på Firemonkey og deres image library i C++ Builder, og jeg kan jo vise med et eksempel hva jeg mener. Jeg brukte et bilde (av meg selv 🙂 ) og gjorde det om til gråskalabilde i PhotoShop.

Deretter laget jeg en «properties» dialogboks i mitt eget program og listet ut de verdiene Firemonkeys bibliotek ga meg. Da kan jeg samtidig vise design av en dialogboks i C++ builder.

Design dialogboks
Dialogboks i C++ Builder
Gråskala fra Photoshop
Et Gråskala bilde fra Photoshop
Properties dialogboks i Firemonkey
«Gråskalabilde» i Firemonkey

I bildet ovenfor ser du hvilke verdier jeg får fra Firemonkeys bibliotek. Hvis du bare skal småfikse litt på bilder fra mobilen, er dette biblioteket mer enn godt nok.

Til profesjonelt bruk er det etter min mening ubrukelig!