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.

Code Samples

Har begynt å legge inn code samples. De finnes i hovedmenyen under:

Eksempler -> Code Samples

Den første som ble lagt inn var en «Properties Dialog». Jeg burde kanskje begynt forfra med program design, TForm-klassen, DocPage, osv. men jeg har egentlig ikke helt bestemt meg for om jeg skal gi ut hele design i full kode.

Vi får se etter hvert som tiden går hvor gavmild jeg blir 🙂

— sd —

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;
}

Dynamisk Meny

Jeg har valgt å generere alle menyene ved runtime, da har jeg full kontroll. Tidligere fiklet jeg litt med C++Builder’s egen internasjonalisering, men den slo ikke helt an hos meg. Jeg bruker i stedet en variant av noe jeg har laget og brukt tidligere.

Der ligger alle menyteksten i en egen fil, og har du behov for oversettelse til et annet språk, sender du bare denne filen til en translatør.

Slik systemet er her nå, lastes det en DLL og ferdig med det, det er greit nok, men det skulle ikke være alt for vanskelig å skrive om dette til et antall DLL-er og angi f.eks. i en ini-fil hvilken som skal lastes.

Systemet er som følger:

Det hele starter i OnFormCreate:

void __fastcall TForm1::OnFormCreate(TObject *Sender)
{
   ---
   ---
   hLibHandle = LoadLibrary( L"DynDllProject.dll" ); // Menu strings

   if( hLibHandle )
	{

	iret = CreateDynMenu( hLibHandle );
        ---
        ---

Ikke noe hokus-pokus i denne funksjonen altså. Alle menyfunksjonene er lagt i «menu1.cpp», du vil finne den kildefilen i prosjektlisten til høyre i RAD Studio.

Hovedfunksjonen, «CreateDynMenu», burde nok kanskje vært skrevet om litt, ingen vanskelighet det heller, men jeg bruker fortsatt gamle ting som jeg vet funker og for å slippe og tenke for mye 🙂 ( Jeg har utelatt detaljer vedr. testing for oversiktens skyld)

int  __fastcall TForm1::CreateDynMenu(HINSTANCE hLibHandle)
{
         ---	
         ---
	CreateFileMenu( hLibHandle );
	CreateEditMenu( hLibHandle );
	CreateSearchMenu( hLibHandle );
	CreateImageMenu( hLibHandle );
         ---
         ---
         ---

Vi kan da gå videre til funksjonene for hver enkelt meny. De er i prinsippet helt like, omtrent som følgende fra File-menyen:

//---------------------------------------------------------------------------
// ------------------------ CreateFileMenu ----------------------------------
//---------------------------------------------------------------------------

int  __fastcall TForm1::CreateFileMenu(HINSTANCE hLibHandle)
{
	TMenuItem *ParentItem;
	TMenuItem *ParentItem2;
	TMenuItem *ChildItem;

	if( hLibHandle != 0)
	{
		charReturnFunc myFunc;

		// GetProcAddress returns a pointer to the loaded method
		myFunc = (charReturnFunc)GetProcAddress(hLibHandle, "GetFileMenuString");

		if( myFunc != 0)
		{
			ParentItem = new TMenuItem(MenuBar1);
			ParentItem->Text = myFunc(0, 256);          // 0 = "File"
			ParentItem->Name = ParentItem->Text;
			MenuBar1->AddObject(ParentItem );

			ChildItem = new TMenuItem(ParentItem);
			ChildItem->Text = myFunc(1, 256);           // 1 = "New"
			ChildItem->Name = ChildItem->Text;
			ChildItem->OnClick = menu_FILE_NEW_Click;
			ParentItem->AddObject(ChildItem);

Først må du hente opp adressen til funksjonen (det er standard bruk av en DLL) og selve menyteksten hentes opp med «ParentItem->Text = myFunc(0, 256)» hvor første parameter er nummeret til tekststringen og det andre tallet er en maks-verdi.

Komplisert? egentlig ikke, men vi er ikke ferdig ennu. Vi skal videre se på de enkelte menyfunksjoner i DLL-en her vist ved parameter 2 i «myfunc», nemlig «GetFileMenuString».

///////////////////////////////////////////////////////////////////////
//
//   wchar_t* GetFileMenuString(UINT uID, int maxlen)
//
//
wchar_t* GetFileMenuString(UINT uID, int maxlen)
{

	switch (uID) {
		case 0:
			return menu_FILE.c_str();                   // index    0
		case 1:
			return menu_FILE_NEW.c_str();               //  1
		case 2:
			return menu_FILE_OPEN.c_str();              //  2
		case 3:
			return menu_FILE_OPEN_RECENT.c_str();       //  3

OK, nå gjenstår det vel bare selve tekststringene som alle ligger i samme fil:

///////////////////////////////////////////////////////////////////////////////
//
// Lots and lots of string defs
//
// FireMonkey does not like resourcefiles, so
// this is my first solution to that problem.
//
// $Rev: 19001 $
//
// Copyright(c) 2019- Gamlisen Norway
//              All rights reserved
//
// ------------------------------------------------------------------
//  File menu textstrings
//
const String menu_FILE = _T("File");                    	// index 	0
const String menu_FILE_NEW = _T("New");                 	//          1
const String menu_FILE_OPEN = _T("Open");               	//          2
const String menu_FILE_OPEN_RECENT = _T("OpenRecent"); 		//          3
const String menu_FILE_CLOSE = _T("CloseFile");        		//          4
const String menu_FILE_CLOSE_ALL = _T("CloseAll");     		//          5
const String menu_FILE_SAVE = _T("SaveFile");          		//          6
const String menu_FILE_SAVE_AS = _T("SaveFileAs");     		//          7
const String menu_FILE_SAVE_PROJECT = _T("SaveProject"); 	//        	8
const String menu_FILE_SAVE_PROJECT_AS = _T("SaveProjectAs"); //  		9

Nå er vi ferdig med alle de enkelte delene som inngår i min form for dynamisk meny.

Komplisert?

Egentlig ikke når du først har forstått systemet 🙂 Samtlige funksjoner blir forklart i detalj på de enkelte sidene.

FotoBox1 Layout

Nå får jeg muligens et lite problem, vil noen si. Det som står her i blogg-strømmen er jo omtrent det samme som finnes rundt omkring på sidene. Det får så være, men det som står her er alt mulig annet rusk og rask også, som f.eks. WordPress-tester (plugins). Jeg kommer sannsynligvis til å legge inn ideer og løsninger for bl.a Lightwave, men her i bloggstrømmen kommer alt helt ustrukturert etter hvert som jeg arbeider meg fremover.

Alt er skrevet i C++ og jeg bruker C++Builder fra RAD Studio (Embarcadero). Layout ved designtidspunkt ser slik ut:

Fotobox1 Layout

Jeg legger ut en TabControl, men foreløpig ingen Tab Items her, de lages ved runtime. Det har jeg gjort ved en ny klasse som er arvet fra TTabItem (jeg skal vise koden om litt).

Årsaken til dette er at den listboksen som vil forekomme på høyre side i programmet skal vise åpne objekter i hver enkelt tab. Jeg prøvde først å legge denne listboksen i hovedklassen, TForm1, men det ble litt komplisert ved at listboksen måtte cleares hver han man gikk inn i en ny tab med pekere frem og tilbake mellom TForm1 og dokumentklassen.

Bildet nedenfor viser hva jeg mener. Dette bildet er fra runtime hvor jeg har åpnet et bilde (av Gamlisen himself 🙂 ). På høyre side ser du her en listbox hvor navnet på åpne bilder settes inn samt visse taster for å skjule bildene, låse dem, osv. finnes.

Det er funksjoner som er tenkt implementert i neste versjon.

Alt dette lages ved File Open:

void __fastcall TForm1::menu_FILE_OPEN_Click(TObject *Sender)
{
	DocPage *NewItem;

	//Show Image files only
	OpenDialog1->Filter = TBitmapCodecManager::GetFilterString();

	if (OpenDialog1->Execute()) {

	try {

		// Add another Tab Item
		NewItem = new DocPage(TabControl1);
		NewItem->Parent = TabControl1;
		NewItem->Text = OpenDialog1->FileName;


		int maxTabs = TabControl1->TabCount;
		TabControl1->TabIndex = maxTabs-1;

		// Right frame containing Layer list, etc.
		NewItem->myFrame = new TFrame2(NewItem);
		NewItem->myFrame->Parent = NewItem;
		NewItem->myFrame->Width = 276;
		NewItem->myFrame->Align = TAlignLayout::Right;


		// 1. TFramedScrollBox
		NewItem->FramedScrollBox1 = new TFramedScrollBox(NewItem);
		NewItem->FramedScrollBox1->Parent = NewItem;
		NewItem->FramedScrollBox1->Align = TAlignLayout::Client;

		// 2. Layout1
		NewItem->Layout1 = new TLayout(NewItem->FramedScrollBox1);
		NewItem->Layout1->Parent = NewItem->FramedScrollBox1;
		NewItem->Layout1->Align = TAlignLayout::Center;

		// 3. Image1
		NewItem->Image1 = new TImage(NewItem->Layout1);
		NewItem->Image1->Parent = NewItem->Layout1;
		NewItem->Image1->Align =  TAlignLayout::Client;

		// Load From File into Image1
		NewItem->Image1->Bitmap->LoadFromFile(OpenDialog1->FileName);

		// Height and width
		NewItem->Layout1->Height = NewItem->Image1->Bitmap->Height;
		NewItem->Layout1->Width = NewItem->Image1->Bitmap->Width;


		// Add to Layer list
		TLayerItem *myLayerItem = new(TLayerItem);

		myLayerItem->FileName = new String (NewItem->Text);

		// Strip off short filename

		String Delimiters = _T("/\\");
		int ix = myLayerItem->FileName->LastDelimiter( Delimiters);
		ix += 1;

		// cheating a little, saying 30 characters as max length :-)
		myLayerItem->ShortName = new String(myLayerItem->FileName->SubString(ix, 30));

		myLayerItem->LayerName = myLayerItem->ShortName;
		myLayerItem->ElementType = File;
		myLayerItem->LayerFilter = 0;
		myLayerItem->Enabled = True;
		myLayerItem->LayerBitmap =  NewItem->Image1->Bitmap;

		NewItem->LayerList.push_back(myLayerItem);
		NewItem->myFrame->LayerListBox1->Items->Add(*myLayerItem->ShortName);
		NewItem->myFrame->TabControl2->ActiveTab = NewItem->myFrame->Layers;
		NewItem->myFrame->TabControl2->TabIndex = 0;
		//NewItem->myFrame->TabControl2->Tabs[2]->Enabled = False;

		//Enable Menu Items after Open File
		int iret = DisableEnableMenuItems(TRUE);

		}
	catch (...) {
		 ShowMessage(" Error from File Open");
		}

	}
}

Slik det er nå i denne versjonen, vil det lages en ny tab-side hver gang man åpner et bilde. Dette er selvfølgelig ikke godt nok i neste versjon. Da skal det være muligheter for flere åpne bilder i hver tab og kunne flytte disse frem og tilbake på siden f.eks.

Plugin for source code

Tester en ny plugin for å vise kildekode. Det er litt knot å få det til i ren WordPress. Denne plugin ser grei ut, uten fargesettinger, men ellers helt grei. Navnet er Code Snippets, merkelig nok 🙂

Koden nedenfor er funksjonen OnFormCreate, jeg tester lasting av diverse stiler og et stykke lenger ned lastes en DLL , DynDllProject.dll. Der ligger alle menyene og helt nederst er det klargjort for en eventuell MAC versjon.

Jeg kunne muligens hatt en try-catch, men pytt, pytt. Jeg tester på lasting av dll-en likevel 🙂

void __fastcall TForm1::OnFormCreate(TObject *Sender)
{
	//TStyleManager::SetStyleFromFile(L"Transparent.style"); 	//  2
	//TStyleManager::SetStyleFromFile(L"MetropolisUIBlack.style");
	//TStyleManager::SetStyleFromFile(L"GoldenGraphite.style");
	//TStyleManager::SetStyleFromFile(L"EmeraldDark.Win.style");
	//TStyleManager::SetStyleFromFile(L"Diamond.Win.style");
	TStyleManager::SetStyleFromFile(L"Dark.style");         	//  1
	//TStyleManager::SetStyleFromFile(L"CalypsoSE_Win.style");    //  3
	//TStyleManager::SetStyleFromFile(L"Calypso_Win.style");
	//TStyleManager::SetStyleFromFile(L"Blend.style");            //  4
	//TStyleManager::SetStyleFromFile(L"AquaGraphite.style");     //  5
	//TStyleManager::SetStyleFromFile(L"Amakrits.style");         //  6
	//TStyleManager::SetStyleFromFile(L"gamlisensteststyle.style");

	//OptionPanel = 0;
	hLibHandle = LoadLibrary( L"DynDllProject.dll" ); // Menu strings
	pmySelection = 0;

	int iret = 0;

	if( hLibHandle )
	{

	iret = CreateDynMenu( hLibHandle );

// ***                                                  ***
// *** Have to do something with the MAC menu later     ***
// ***                                                  ***
#ifdef macos

	//winabout.Visible = False;
	//winline.Visible = False;
	//winexit.Visible = False;
	//macquit.ShortCut = scCommand or Ord('Q');

#else

	//MacAbout.Visible = False;
	//macline.Visible = False;
	//macquit.Visible = False;

#endif

	}

	ZoomTrackBar->Value = 1;
}

Gråtoner og andre toner

Hvorfor «ødelegger» Firemonkey bildene? Hæææ? Ødelegger??? Yess Sir, de gjør om alle bildeformater internt til RGB!

Jeg tenkte ikke over det før jeg ønsket å få bildeinfo fra biblioteket. Uansett hvilket bilde jeg lastet opp («åpnet»), fikk jeg til svar at det var 32 bit RGB! Det betyr 3×8 bit + alpha.

Etter et par dager med hardkjøring av Google, var svaret gitt. Det bare var sånn!

Hva betydde det for meg? OK, Hvordan lages gråtoner f.eks. på skjermen? Jadajada, skjermen er RGB den! Oissann! Hva med printeren da? Den bruker CMYK, helsort farge og rasterteknikk, min venn! Gråtoner finnes ikke i vår daglige verden!

Finnes det egentlig et sort-hvitt kamera i dag? Jeg er ikke fotograf, så jeg vet egentlig ikke. Jeg tar sjansen og sier nei. Du må antagelig tilbake til de gamle analoge kameraene, med film. Det finnes digitale kamera som tar B&W 🙂

Det finnes en rekke andre spesialformater, jeg er klar over det, men til daglig bruk, ordne og fikse litt på bilder fra mobilen, så er Firemonkey grafikkbibliotek fullt ut brukbart, terningkast 6.

Til profesjonelt bruk, er det ubrukelig.

Et gråtone-bilde fra mitt program:

Gamlisen

Kodeeksempler

Jeg har noen kodeeksempler som for det meste er tilpasset mitt halvferdige program. Alle eksemplene er skrevet for å være instruktive, enkle å forstå og ikke for å være mest mulige effektive.

Som pensjonist har jeg ganske god tid til å drive med det jeg vil, og jeg bestemte meg for å lage en «Photoshop»-klone 🙂 Ikke fordi jeg er misfornøyd med PhotoShop, eller fordi jeg tror jeg kan lage et mye, bedre program, men mest fordi programmering er en av mine hobby.

Pr i dag ser programmet slik ut:

Gamlisens Program

I RAD Studio ser det under kodearbeidet slik ut:

På bildet ovenfor kan du se prosjektet består av et hovedprogram og en DLL, DLL-en er for dynamisk lasting av menyene, og under applikasjonen kan du se at det allerede nå er testet ut en del filtre.

Det har foreløpig stoppet opp lite grann fordi jeg ble litt (ganske meget egentlig 🙁 ) skuffet over at det grafiske biblioteket til Firemonkey gjør om alle bilder til 32 Bits RGB internt (Dette gjelder i hvert fall i dag, 16.Jan 2020).

Så et lite video-eksempel laget i Lightwave, modellen i Modeler og animasjonen i Layout. Husker ikke sikert, men tror det hele ble satt sammen i  Adobe Premiere Pro, eller Corel VideoStudio.

Du kan faktisk kjøre den i fullscreen ved å klikke på den lille firkanten til høyre for høyttaleren. Du må da selvfølgelig trykke Esc-tasten for å komme ut av Fullscreen modus 🙂

Denne videoen er litt over 25 MB, ikke store greiene m.a.o men det funker, og det var faktisk mulig å laste den ned 🙂